diff options
Diffstat (limited to 'firmware/microblaze/apps')
48 files changed, 8133 insertions, 0 deletions
diff --git a/firmware/microblaze/apps/bitrot/tx_drop.c b/firmware/microblaze/apps/bitrot/tx_drop.c new file mode 100644 index 000000000..3a336e938 --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop.c @@ -0,0 +1,261 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * Like tx_only.c, but we discard data packets instead of sending them to the + * DSP TX pipeline. + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = MASTER_CLK_RATE/1000; // tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu +//#define CPU_TX_BUF 1 // cpu -> eth + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + + +/* + * ================================================================ + * configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE 4 +#define DSP_TX_SAMPLES_PER_FRAME 250 // not used except w/ debugging +#define DSP_TX_EXTRA_LINES 2 // reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past ethernet header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ + putchar('U'); + + dbsm_stop(&dsp_tx_sm); + dsp_tx_regs->clear_state = 1; + dbsm_start(&dsp_tx_sm); // restart sm so we're listening to ethernet again + + // putstr("\nirq: underrun\n"); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 256; + int interp = 32; + + op_config_tx_t def_config; + memset(&def_config, 0, sizeof(def_config)); + def_config.phase_inc = 408021893; // 9.5 MHz [2**32 * fc/fsample] + def_config.scale_iq = (tx_scale << 16) | tx_scale; + def_config.interp = interp; + + // setup Tx DSP regs + config_tx_cmd(&def_config); +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + if (status & BPS_ERROR_ALL){ + // FIXME rare path, handle error conditions + putstr("Errors! status = "); + puthex32_nl(status); + + printf("total_rx_pkts = %d\n", total_rx_pkts); + printf("total_rx_bytes = %d\n", total_rx_bytes); + + print_rmon_regs(); + + if (status & (BPS_ERROR(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_1))){ + dbsm_stop(&dsp_tx_sm); + dsp_tx_regs->clear_state = 1; // try to restart + dbsm_start(&dsp_tx_sm); + return; + } + } + + dbsm_process_status(&dsp_tx_sm, status); + + if (status & BPS_DONE(CPU_TX_BUF)){ + bp_clear_buf(CPU_TX_BUF); + } +} + + +/* + * Called when an ethernet packet is received. + * + * Claim that we handled all the packets, + * dropping those destined for the TX DSP chain + * on the ground. + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + hal_toggle_leds(0x1); + + u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); + size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + + total_rx_pkts++; + total_rx_bytes += byte_len; + + // inspect rcvd frame and figure out what do do. + + if (pkt->ehdr.ethertype != U2_ETHERTYPE) + return true; // ignore, probably bogus PAUSE frame from MAC + + int chan = u2p_chan(&pkt->fixed); + + switch (chan){ + case CONTROL_CHAN: + handle_control_chan_frame(pkt, byte_len); + return true; // we handled the packet + break; + + case 0: + default: + return true; // We handled the data by dropping it :) + break; + } +} + + +int +main(void) +{ + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); + hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1); + + putstr("\ntx_drop\n"); + + // Control LEDs + hal_set_leds(0x0, 0x3); + + pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + nop_eth_pkt_inspector); + + // program tx registers + setup_tx(); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + while(1){ + buffer_irq_handler(0); + } +} + diff --git a/firmware/microblaze/apps/bitrot/tx_drop2.c b/firmware/microblaze/apps/bitrot/tx_drop2.c new file mode 100644 index 000000000..3afd722e6 --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop2.c @@ -0,0 +1,292 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * Like tx_only.c, but we discard data packets instead of sending them to the + * DSP TX pipeline. + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = MASTER_CLK_RATE/1000; // tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu +//#define CPU_TX_BUF 1 // cpu -> eth + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + + +/* + * ================================================================ + * configure DSP RX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE 5 +#define DSP_RX_SAMPLES_PER_FRAME 128 +#define DSP_RX_EXTRA_LINES 1 // writes timestamp + +// Receive from DSP Rx +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ethernet +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from last_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + +/* + * ================================================================ + * configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE 4 +#define DSP_TX_SAMPLES_PER_FRAME 250 // not used except w/ debugging +#define DSP_TX_EXTRA_LINES 2 // reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past ethernet header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ + putchar('U'); + + dbsm_stop(&dsp_tx_sm); + dsp_tx_regs->clear_state = 1; + dbsm_start(&dsp_tx_sm); // restart sm so we're listening to ethernet again + + // putstr("\nirq: underrun\n"); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + +#if 1 + int tx_scale = 256; + int interp = 32; + + op_config_tx_t def_config; + memset(&def_config, 0, sizeof(def_config)); + def_config.phase_inc = 408021893; // 9.5 MHz [2**32 * fc/fsample] + def_config.scale_iq = (tx_scale << 16) | tx_scale; + def_config.interp = interp; + + // setup Tx DSP regs + config_tx_cmd(&def_config); +#endif +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + if (status & BPS_ERROR_ALL){ + // FIXME rare path, handle error conditions + putstr("Errors! status = "); + puthex32_nl(status); + + printf("total_rx_pkts = %d\n", total_rx_pkts); + printf("total_rx_bytes = %d\n", total_rx_bytes); + + print_rmon_regs(); + + if (status & (BPS_ERROR(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_1))){ + dbsm_stop(&dsp_tx_sm); + dsp_tx_regs->clear_state = 1; // try to restart + dbsm_start(&dsp_tx_sm); + return; + } + } + + dbsm_process_status(&dsp_tx_sm, status); + + if (status & BPS_DONE(CPU_TX_BUF)){ + bp_clear_buf(CPU_TX_BUF); + } +} + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here (always!) + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + hal_toggle_leds(0x1); + + u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); + size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + + total_rx_pkts++; + total_rx_bytes += byte_len; + + // inspect rcvd frame and figure out what do do. + + if (pkt->ehdr.ethertype != U2_ETHERTYPE) + return true; // ignore, probably bogus PAUSE frame from MAC + + int chan = u2p_chan(&pkt->fixed); + + switch (chan){ + case CONTROL_CHAN: + handle_control_chan_frame(pkt, byte_len); + return true; // we handled the packet + break; + + case 0: + default: + return true; // say we handled it + break; + } +} + + +int +main(void) +{ + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); + hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1); // no printing... + + putstr("\ntx_drop2\n"); + + // Control LEDs + hal_set_leds(0x0, 0x3); + + // pic_register_handler(IRQ_OVERRUN, overrun_irq_handler); + pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + + //pic_register_handler(IRQ_TIMER, timer_irq_handler); + //hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + + ethernet_init(); + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + nop_eth_pkt_inspector); + + // program tx registers + setup_tx(); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + while(1){ + buffer_irq_handler(0); + } +} + diff --git a/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c b/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c new file mode 100644 index 000000000..2b8db7f7d --- /dev/null +++ b/firmware/microblaze/apps/bitrot/tx_drop_rate_limited.c @@ -0,0 +1,233 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include "print_rmon_regs.h" +#include "eth_mac.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * receive packets from ethernet at a fixed rate and discard them + */ + +int total_rx_pkts = 0; +int total_rx_bytes = 0; + + +static int timer_delta = (int)(MASTER_CLK_RATE * 10e-6); // 10us / tick + + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu +//#define CPU_TX_BUF 1 // cpu -> eth + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +static volatile bool receive_packet_now = false; + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout + receive_packet_now = true; +} + + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ + putchar('U'); +} + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 256; + int interp = 32; + + op_config_tx_t def_config; + memset(&def_config, 0, sizeof(def_config)); + def_config.phase_inc = 408021893; // 9.5 MHz [2**32 * fc/fsample] + def_config.scale_iq = (tx_scale << 16) | tx_scale; + def_config.interp = interp; + + // setup Tx DSP regs + config_tx_cmd(&def_config); +} + + +/* + * Called when an ethernet packet is received. + * + * Claim that we handled all the packets, + * dropping those destined for the TX DSP chain + * on the ground. + */ +bool +nop_eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + hal_toggle_leds(0x1); + + u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); + size_t byte_len = (buffer_pool_status->last_line[bufno] - 1) * 4; + + total_rx_pkts++; + total_rx_bytes += byte_len; + + // inspect rcvd frame and figure out what do do. + + if (pkt->ehdr.ethertype != U2_ETHERTYPE) + return true; // ignore, probably bogus PAUSE frame from MAC + + int chan = u2p_chan(&pkt->fixed); + + switch (chan){ + case CONTROL_CHAN: + handle_control_chan_frame(pkt, byte_len); + return true; // we handled the packet + break; + + case 0: + default: + return true; // We handled the data by dropping it :) + break; + } +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + if (status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) + bp_clear_buf(CPU_TX_BUF); + + if (status & (BPS_DONE(DSP_TX_BUF_0) | BPS_ERROR(DSP_TX_BUF_0))){ + bp_clear_buf(DSP_TX_BUF_0); + + if (status & BPS_ERROR(DSP_TX_BUF_0)){ + int crc = eth_mac_read_rmon(0x05); + int fifo_full = eth_mac_read_rmon(0x06); + int too_short_too_long = eth_mac_read_rmon(0x07); + putstr("Errors! status = "); + puthex32_nl(status); + + printf("crc_err\t\t= %d\n", crc); + printf("fifo_full\t\t= %d\n", fifo_full); + printf("too_short_too_long\t= %d\n", too_short_too_long); + + printf("total_rx_pkts = %d\n", total_rx_pkts); + printf("total_rx_bytes = %d\n", total_rx_bytes); + } + else + nop_eth_pkt_inspector(0, DSP_TX_BUF_0); + } + + if (receive_packet_now && (status & BPS_IDLE(DSP_TX_BUF_0))){ + receive_packet_now = false; + bp_receive_to_buf(DSP_TX_BUF_0, PORT_ETH, 1, 0, BP_LAST_LINE); + } +} + + +int +main(void) +{ + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + hal_gpio_set_tx_mode(15, 0, GPIOM_FPGA_1); + hal_gpio_set_rx_mode(15, 0, GPIOM_FPGA_1); + + putstr("\ntx_drop_rate_limited\n"); + + // Control LEDs + hal_set_leds(0x0, 0x3); + + pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + + pic_register_handler(IRQ_TIMER, timer_irq_handler); + hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + // program tx registers + setup_tx(); + + // start a receive from ethernet + bp_receive_to_buf(DSP_TX_BUF_0, PORT_ETH, 1, 0, BP_LAST_LINE); + + while(1){ + buffer_irq_handler(0); + } +} + 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/cruft/Makefile.am b/firmware/microblaze/apps/cruft/Makefile.am new file mode 100644 index 000000000..a4f79935b --- /dev/null +++ b/firmware/microblaze/apps/cruft/Makefile.am @@ -0,0 +1,82 @@ +# +# Copyright 2010 Ettus Research LLC +# +# Copyright 2007,2008 Free Software Foundation, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +include $(top_srcdir)/Makefile.common + +LDADD = $(top_srcdir)/lib/libu2fw.a + +AM_CFLAGS += -I$(top_srcdir)/../../host/lib/usrp + +noinst_PROGRAMS = txrx_uhd.elf + +# blink_leds \ +# blink_leds2 \ +# buf_ram_test \ +# burn_dbsrx_eeprom \ +# can_i_sub \ +# echo \ +# hello \ +# read_dbids \ +# set_hw_rev \ +# test1 \ +# test_db_spi \ +# test_i2c \ +# test_sd \ +# test_ram \ +# test_phy_comm \ +# test_lsadc \ +# test_lsdac \ +# timer_test \ +# txrx \ +# burnrev30 \ +# burnrev31 \ +# burnrev40 \ +# sd_gentest \ +# sd_bounce +# + +#nononono = \ +# eth_serdes \ +# gen_eth_packets \ +# rcv_eth_packets \ +# tx_standalone \ +# factory_test \ +# serdes_txrx \ +# mimo_tx \ +# mimo_tx_slave \ +# ibs_rx_test \ +# ibs_tx_test + +# tx_drop_SOURCES = tx_drop.c app_common.c +# tx_drop_rate_limited_SOURCES = tx_drop_rate_limited.c app_common.c +# tx_drop2_SOURCES = tx_drop2.c app_common.c +txrx_uhd_elf_SOURCES = txrx_uhd.c +# app_common_v2.c +#factory_test_SOURCES = factory_test.c app_common_v2.c +#eth_serdes_SOURCES = eth_serdes.c app_passthru_v2.c +#serdes_txrx_SOURCES = serdes_txrx.c app_common_v2.c +#mimo_tx_SOURCES = mimo_tx.c mimo_app_common_v2.c +#mimo_tx_slave_SOURCES = mimo_tx_slave.c app_common_v2.c + +#noinst_HEADERS = \ +# app_common_v2.h \ +# app_passthru_v2.h \ +# mimo_app_common_v2.h +# + diff --git a/firmware/microblaze/apps/cruft/app_passthru_v2.c b/firmware/microblaze/apps/cruft/app_passthru_v2.c new file mode 100644 index 000000000..406c56b3b --- /dev/null +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.c @@ -0,0 +1,251 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "app_passthru_v2.h" +#include "buffer_pool.h" +#include "memcpy_wa.h" +#include "ethernet.h" +#include "nonstdio.h" +#include "print_rmon_regs.h" +#include "db.h" +#include "clocks.h" +#include <string.h> + +volatile bool link_is_up = false; // eth handler sets this + + +// If this is non-zero, this dbsm could be writing to the ethernet +dbsm_t *ac_could_be_sending_to_eth; + +//static unsigned char exp_seqno = 0; + +void +set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt) +{ + reply_pkt->ehdr.dst = cmd_pkt->ehdr.src; + reply_pkt->ehdr.src = *ethernet_mac_addr(); + reply_pkt->ehdr.ethertype = U2_ETHERTYPE; + reply_pkt->thdr.flags = 0; + reply_pkt->thdr.fifo_status = 0; // written by protocol engine + reply_pkt->thdr.seqno = 0; // written by protocol engine + reply_pkt->thdr.ack = 0; // written by protocol engine + u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN); + reply_pkt->fixed.timestamp = timer_regs->time; +} + +static void +send_reply(unsigned char *reply, size_t reply_len) +{ + if (reply_len < 64) + reply_len = 64; + + // wait for buffer to become idle + hal_set_leds(0x4, 0x4); + while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) + ; + hal_set_leds(0x0, 0x4); + + // copy reply into CPU_TX_BUF + memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len); + + // wait until nobody else is sending to the ethernet + if (ac_could_be_sending_to_eth){ + hal_set_leds(0x8, 0x8); + dbsm_wait_for_opening(ac_could_be_sending_to_eth); + hal_set_leds(0x0, 0x8); + } + + // fire it off + bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, reply_len/4); + + // wait for it to complete (not long, it's a small pkt) + while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) + ; + + bp_clear_buf(CPU_TX_BUF); +} + + +static size_t +op_id_cmd(const op_generic_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_id_reply_t *r = (op_id_reply_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) // no room + return 0; + + // Build reply subpacket + + r->opcode = OP_ID_REPLY; + r->len = sizeof(op_id_reply_t); + r->rid = p->rid; + r->addr = *ethernet_mac_addr(); + r->hw_rev = 0x0000; // FIXME + // r->fpga_md5sum = ; // FIXME + // r->sw_md5sum = ; // FIXME + + // FIXME Add d'board info, including dbid, min/max gain, min/max freq + + return r->len; +} + +static size_t +add_eop(void *reply_payload, size_t reply_payload_space) +{ + op_generic_t *r = (op_generic_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + r->opcode = OP_EOP; + r->len = sizeof(*r); + r->rid = 0; + r->ok = 0; + + return r->len; +} + +bool +handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) +{ + unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; + unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; + int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); + + bool handled_it = false; + + // initialize reply + memset(reply, 0, sizeof(reply)); + set_reply_hdr((u2_eth_packet_t *) reply, pkt); + + // point to beginning of payload (subpackets) + unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); + int payload_len = len - sizeof(u2_eth_packet_t); + + size_t subpktlen = 0; + + while (payload_len >= sizeof(op_generic_t)){ + const op_generic_t *gp = (const op_generic_t *) payload; + subpktlen = 0; + + switch(gp->opcode){ + case OP_EOP: // end of subpackets + goto end_of_subpackets; + + case OP_ID: + subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); + handled_it = true; + break; + + default: + if (0){ + printf("\npassing on %d\n", gp->opcode); + } + break; + } + + int t = (gp->len + 3) & ~3; // bump to a multiple of 4 + payload += t; + payload_len -= t; + + subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 + reply_payload += subpktlen; + reply_payload_space -= subpktlen; + } + + end_of_subpackets: + + if (handled_it){ + // add the EOP marker + subpktlen = add_eop(reply_payload, reply_payload_space); + subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 + reply_payload += subpktlen; + reply_payload_space -= subpktlen; + + send_reply(reply, reply_payload - reply); + } + + return handled_it; +} + + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +bool +eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); + size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4; + + //static size_t last_len = 0; + + // hal_toggle_leds(0x1); + + // inspect rcvd frame and figure out what do do. + + if (pkt->ehdr.ethertype != U2_ETHERTYPE) + return true; // ignore, probably bogus PAUSE frame from MAC + + int chan = u2p_chan(&pkt->fixed); + + switch (chan){ + case CONTROL_CHAN: + return handle_control_chan_frame(pkt, byte_len); + break; + + case 0: + default: +#if 0 + if (last_len != 0){ + if (byte_len != last_len){ + printf("Len: %d last: %d\n", byte_len, last_len); + } + } + last_len = byte_len; + + if((pkt->thdr.seqno) == exp_seqno){ + exp_seqno++; + //putchar('.'); + } + else { + // putchar('S'); + //printf("S%d %d ",exp_seqno,pkt->thdr.seqno); + exp_seqno = pkt->thdr.seqno + 1; + } +#endif + return false; // pass it on to Tx DSP + break; + } +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + link_is_up = speed != 0; + hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); + printf("\neth link changed: speed = %d\n", speed); +} diff --git a/firmware/microblaze/apps/cruft/app_passthru_v2.h b/firmware/microblaze/apps/cruft/app_passthru_v2.h new file mode 100644 index 000000000..3904c670f --- /dev/null +++ b/firmware/microblaze/apps/cruft/app_passthru_v2.h @@ -0,0 +1,54 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_APP_COMMON_H +#define INCLUDED_APP_COMMON_H + +#include <stdbool.h> +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "memory_map.h" +#include "hal_io.h" +#include <stddef.h> +#include <db.h> + +#define CPU_TX_BUF 7 // cpu -> eth + +#define _AL4 __attribute__((aligned (4))) + +extern volatile bool link_is_up; // eth handler sets this + + +// If there's a dbsm that sends to the ethernet, put it's address here +extern dbsm_t *ac_could_be_sending_to_eth; + + +void set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt); + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +bool eth_pkt_inspector(dbsm_t *sm, int bufno); + +void link_changed_callback(int speed); + +bool handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len); + +#endif /* INCLUDED_APP_COMMON_H */ diff --git a/firmware/microblaze/apps/cruft/blink_leds.c b/firmware/microblaze/apps/cruft/blink_leds.c new file mode 100644 index 000000000..682ca8db2 --- /dev/null +++ b/firmware/microblaze/apps/cruft/blink_leds.c @@ -0,0 +1,40 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "nonstdio.h" + +int +main(void) +{ + int counter = 0; + + u2_init(); + + putstr("blink_leds\n"); + while(1){ + output_regs->leds = (counter++ & 0x3); + } + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/blink_leds2.c b/firmware/microblaze/apps/cruft/blink_leds2.c new file mode 100644 index 000000000..13e78afb3 --- /dev/null +++ b/firmware/microblaze/apps/cruft/blink_leds2.c @@ -0,0 +1,53 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "pic.h" +#include "nonstdio.h" + +//#define DELTA_T (MASTER_CLK_RATE/2) // 0.5s (10ns per tick) +#define DELTA_T 5000 // 5 us (10ns per tick) + + +void +timer_handler(unsigned irq) +{ + hal_set_timeout(DELTA_T); // schedule next timeout + hal_toggle_leds(0x2); +} + +int +main(void) +{ + u2_init(); + + putstr("blink_leds2\n"); + pic_register_handler(IRQ_ONETIME, timer_handler); + hal_set_timeout(DELTA_T); // schedule next timeout + + while(1){ + hal_toggle_leds(0x1); + } + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/buf_ram_test.c b/firmware/microblaze/apps/cruft/buf_ram_test.c new file mode 100644 index 000000000..1aca2aec5 --- /dev/null +++ b/firmware/microblaze/apps/cruft/buf_ram_test.c @@ -0,0 +1,89 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "hal_io.h" +#include "mdelay.h" + + +static void +write_bufs(void) +{ + int i, n; + int counter = 0; + + for (n = 0; n < NBUFFERS; n++){ + volatile int *p = buffer_ram(n); + for (i = 0; i < BP_NLINES; i++) + p[i] = counter++; + } +} + +// return number of errors detected +static int +check_bufs(void) +{ + int i, n; + int counter = 0; + int nerrors = 0; + + for (n = 0; n < NBUFFERS; n++){ + volatile int *p = buffer_ram(n); + for (i = 0; i < BP_NLINES; i++, counter++){ + int rd = p[i]; + if (rd != counter){ + putchar('b'); + putchar(n + '0'); + putchar('['); + puthex16(i); + putstr("] exp: "); + puthex32(counter); + putstr(" got: "); + puthex32_nl(rd); + nerrors++; + } + } + } + return nerrors; +} + + +int +main(void) +{ + u2_init(); + + output_regs->leds = 0; + + write_bufs(); + int nerrors = check_bufs(); + + if (nerrors == 0){ + output_regs->leds = 0x3; // leds on -> PASS + putstr("PASS\n"); + } + else { + output_regs->leds = 0x0; // leds off -> FAIL + putstr("FAIL\n"); + } + + hal_finish(); + return 0; +} diff --git a/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c new file mode 100644 index 000000000..116d4d8d0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burn_dbsrx_eeprom.c @@ -0,0 +1,106 @@ +/* -*- 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "i2c.h" +#include "usrp2_i2c_addr.h" +#include "mdelay.h" +#include "hal_io.h" +#include "nonstdio.h" +#include <stdbool.h> + + + +int read_dboard_eeprom(int i2c_addr); + + +#define USRP_DBID_DBS_RX 0x0002 +#define USRP_DBID_DBS_RX_WITH_CLOCK_MOD 0x000d + +const char dbs_rx_rev2_eeprom[] = { + 0xdb, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 +}; + +#define LED_VALS (LED_A | LED_B | LED_C | LED_D) +#define LED_MASK (LED_A | LED_B | LED_C | LED_D) + +int +main(void) +{ + u2_init(); + + puts("\nburn_dbsrx_eeprom\n"); + + hal_set_leds(0, ~0); // all off + + int i2c_addr = I2C_ADDR_RX_A; + int dbid = read_dboard_eeprom(i2c_addr); + bool ok; + const char *msg = 0; + + switch (dbid){ + case -1: + msg = "No RX daughterboard found"; + goto bad; + + case -2: + msg = "Invalid RX EEPROM contents"; + goto bad; + + case USRP_DBID_DBS_RX_WITH_CLOCK_MOD: + msg = "RX Daughterboard already reports being a DBS RX w/ CLOCK_MOD"; + goto good; + + case USRP_DBID_DBS_RX: + // Says it's a DBS_RX, attempt to burn the EEPROM + ok = eeprom_write(i2c_addr, 0, + dbs_rx_rev2_eeprom, sizeof(dbs_rx_rev2_eeprom)); + if (ok){ + msg = "Successfully programmed db as DBS RX Rev 2.1"; + goto good; + } + else { + msg = "Failed to write daugherboard eeprom"; + goto bad; + } + + default: + msg = "Daughterboard is not a DBS RX; ignored"; + goto bad; + } + + good: + puts(msg); + hal_set_leds(LED_VALS, LED_MASK); + while (1) + ; + + bad: + puts(msg); + while(1){ + hal_toggle_leds(LED_VALS); + mdelay(50); + } +} diff --git a/firmware/microblaze/apps/cruft/burnrev30.c b/firmware/microblaze/apps/cruft/burnrev30.c new file mode 100644 index 000000000..40fa53e34 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burnrev30.c @@ -0,0 +1,162 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" +#include "mdelay.h" + +#define HW_REV_MAJOR 3 +#define HW_REV_MINOR 0 + +int test_ram() +{ + int i,j,k; + output_regs->ram_page = 1<<10; + + extram[0] = 0xDEADBEEF; + extram[1] = 0xF00D1234; + extram[7] = 0x76543210; + + output_regs->ram_page = 2<<10; + extram[7] = 0x55555555; + extram[1] = 0xaaaaaaaa; + extram[0] = 0xeeeeeeee; + + output_regs->ram_page = 1<<10; + + i = extram[0]; + k = extram[1]; + j = extram[7]; + + if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { + puts("RAM FAIL1!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + + output_regs->ram_page = 2<<10; + + j = extram[7]; + k = extram[1]; + i = extram[0]; + + if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { + puts("RAM FAIL2!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + return 1; +} + +int test_sd() +{ + int i = sd_init(); + if(i==0) { + puts("FAILED INIT of Card\n"); + return 0; + } + + unsigned char buf[512]; + i = sd_read_block(2048,buf); + if(i == 0) { + puts("READ Command Rejected\n"); + return 0; + } + if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) + ; + else { + puts("Read bad data from SD Card\n"); + return 0; + } + return 1; +} + +int +main(void) +{ + u2_init(); + + putstr("\nFactory Test, Board Rev 3.0\n"); + + bool ok = true; + unsigned char maj = HW_REV_MAJOR; + unsigned char min = HW_REV_MINOR; + ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); + ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + + putstr("\nset_hw_rev\n"); + if (ok) + printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + else { + printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + hal_finish(); + return 0; + } + + if(test_sd()) + puts("SD OK\n"); + else { + puts("SD FAIL\n"); + //hal_finish(); + //return 0; + } + if(test_ram()) + puts("RAM OK\n"); + else { + puts("RAM FAIL\n"); + hal_finish(); + return 0; + } + + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + + clocks_mimo_config(MC_WE_LOCK_TO_SMA); + + while (!clocks_lock_detect()) { + puts("No Lock"); + mdelay(1000); + } + puts("Clock Locked\n"); + +} diff --git a/firmware/microblaze/apps/cruft/burnrev31.c b/firmware/microblaze/apps/cruft/burnrev31.c new file mode 100644 index 000000000..f6b08d187 --- /dev/null +++ b/firmware/microblaze/apps/cruft/burnrev31.c @@ -0,0 +1,162 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" +#include "mdelay.h" + +#define HW_REV_MAJOR 3 +#define HW_REV_MINOR 1 + +int test_ram() +{ + int i,j,k; + output_regs->ram_page = 1<<10; + + extram[0] = 0xDEADBEEF; + extram[1] = 0xF00D1234; + extram[7] = 0x76543210; + + output_regs->ram_page = 2<<10; + extram[7] = 0x55555555; + extram[1] = 0xaaaaaaaa; + extram[0] = 0xeeeeeeee; + + output_regs->ram_page = 1<<10; + + i = extram[0]; + k = extram[1]; + j = extram[7]; + + if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { + puts("RAM FAIL1!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + + output_regs->ram_page = 2<<10; + + j = extram[7]; + k = extram[1]; + i = extram[0]; + + if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { + puts("RAM FAIL2!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + return 1; +} + +int test_sd() +{ + int i = sd_init(); + if(i==0) { + puts("FAILED INIT of Card\n"); + return 0; + } + + unsigned char buf[512]; + i = sd_read_block(2048,buf); + if(i == 0) { + puts("READ Command Rejected\n"); + return 0; + } + if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) + ; + else { + puts("Read bad data from SD Card\n"); + return 0; + } + return 1; +} + +int +main(void) +{ + u2_init(); + + putstr("\nFactory Test, Board Rev 3.1\n"); + + bool ok = true; + unsigned char maj = HW_REV_MAJOR; + unsigned char min = HW_REV_MINOR; + ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); + ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + + putstr("\nset_hw_rev\n"); + if (ok) + printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + else { + printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + hal_finish(); + return 0; + } + + if(test_sd()) + puts("SD OK\n"); + else { + puts("SD FAIL\n"); + //hal_finish(); + //return 0; + } + if(test_ram()) + puts("RAM OK\n"); + else { + puts("RAM FAIL\n"); + hal_finish(); + return 0; + } + + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + + clocks_mimo_config(MC_WE_LOCK_TO_SMA); + + while (!clocks_lock_detect()) { + puts("No Lock"); + mdelay(1000); + } + puts("Clock Locked\n"); + +} diff --git a/firmware/microblaze/apps/cruft/can_i_sub.c b/firmware/microblaze/apps/cruft/can_i_sub.c new file mode 100644 index 000000000..ed49791f0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/can_i_sub.c @@ -0,0 +1,25 @@ +#include <u2_init.h> +#include <nonstdio.h> + +//typedef long long int64_t; + + +int64_t sub(int64_t a, int64_t b); +void print(int64_t d); + +int main(void) +{ + u2_init(); + + int64_t d = sub(462550990848000LL, 462028800000000LL); + print_uint64(d); + newline(); + return 0; +} + +int64_t sub(int64_t a, int64_t b) +{ + return a - b; +} + + diff --git a/firmware/microblaze/apps/cruft/double_buffer_fragment.c b/firmware/microblaze/apps/cruft/double_buffer_fragment.c new file mode 100644 index 000000000..cfc061247 --- /dev/null +++ b/firmware/microblaze/apps/cruft/double_buffer_fragment.c @@ -0,0 +1,138 @@ +#if 0 +void +double_buffering(int port) { + unsigned int localstatus = buffer_pool_status->status; + + if(localstatus & BPS_DONE_0) { + bp_clear_buf(0); + if(buffer_state[0] == FILLING) { + buffer_state[0] = FULL; + if(buffer_state[1] == EMPTY) { + bp_receive_to_buf(1, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[1] = FILLING; + } + else + dsp_rx_idle = 1; + if(serdes_tx_idle) { + serdes_tx_idle = 0; + bp_send_from_buf(0, port, 1, 10, 509); // SERDES_TX from buffer 0 + buffer_state[0] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[0] = EMPTY; + if(dsp_rx_idle) { + dsp_rx_idle = 0; + bp_receive_to_buf(0, 1, 1, 10, 509); // DSP_RX to buffer 0, use 500 lines + buffer_state[0] = FILLING; + } + if(buffer_state[1] == FULL) { + bp_send_from_buf(1, port, 1, 10, 509); // SERDES_TX from buffer 1 + buffer_state[1] = EMPTYING; + } + else + serdes_tx_idle = 1; + } + putstr("Int Proc'ed 0\n"); + } + + if(localstatus & BPS_DONE_1) { + bp_clear_buf(1); + if(buffer_state[1] == FILLING) { + buffer_state[1] = FULL; + if(buffer_state[0] == EMPTY) { + bp_receive_to_buf(0, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[0] = FILLING; + } + else + dsp_rx_idle = 1; + if(serdes_tx_idle) { + serdes_tx_idle = 0; + bp_send_from_buf(1, port, 1, 10, 509); // SERDES_TX from buffer 1 + buffer_state[1] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[1] = EMPTY; + if(dsp_rx_idle) { + dsp_rx_idle = 0; + bp_receive_to_buf(1, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[1] = FILLING; + } + if(buffer_state[0] == FULL) { + bp_send_from_buf(0, port, 1, 10, 509); // SERDES_TX from buffer 0 + buffer_state[0] = EMPTYING; + } + else + serdes_tx_idle = 1; + } + putstr("Int Proc'ed 1\n"); + } + + if(localstatus & BPS_DONE_2) { + bp_clear_buf(2); + if(buffer_state[2] == FILLING) { + buffer_state[2] = FULL; + if(buffer_state[3] == EMPTY) { + bp_receive_to_buf(3, port, 1, 5, 504); // SERDES_RX to buffer 3, use 500 lines + buffer_state[3] = FILLING; + } + else + serdes_rx_idle = 1; + if(dsp_tx_idle) { + dsp_tx_idle = 0; + bp_send_from_buf(2, 1, 1, 5, 504); // DSP_TX from buffer 2 + buffer_state[2] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[2] = EMPTY; + if(serdes_rx_idle) { + serdes_rx_idle = 0; + bp_receive_to_buf(2, port, 1, 5, 504); // SERDES_RX to buffer 2 + buffer_state[2] = FILLING; + } + if(buffer_state[3] == FULL) { + bp_send_from_buf(3, 1, 1, 5, 504); // DSP_TX from buffer 3 + buffer_state[3] = EMPTYING; + } + else + dsp_tx_idle = 1; + } + putstr("Int Proc'ed 2\n"); + } + + if(localstatus & BPS_DONE_3) { + bp_clear_buf(3); + if(buffer_state[3] == FILLING) { + buffer_state[3] = FULL; + if(buffer_state[2] == EMPTY) { + bp_receive_to_buf(2, port, 1, 5, 504); // SERDES_RX to buffer 2, use 500 lines + buffer_state[2] = FILLING; + } + else + serdes_rx_idle = 1; + if(dsp_tx_idle) { + dsp_tx_idle = 0; + bp_send_from_buf(3, 1, 1, 5, 504); // DSP_TX from buffer 3 + buffer_state[3] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[3] = EMPTY; + if(serdes_rx_idle) { + serdes_rx_idle = 0; + bp_receive_to_buf(3, port, 1, 5, 504); // SERDES_RX to buffer 3 + buffer_state[3] = FILLING; + } + if(buffer_state[2] == FULL) { + bp_send_from_buf(2, 1, 1, 5, 504); // DSP_TX from buffer 2 + buffer_state[2] = EMPTYING; + } + else + dsp_tx_idle = 1; + } + putstr("Int Proc'ed 3\n"); + } +} +#endif diff --git a/firmware/microblaze/apps/cruft/echo.c b/firmware/microblaze/apps/cruft/echo.c new file mode 100644 index 000000000..89108ee80 --- /dev/null +++ b/firmware/microblaze/apps/cruft/echo.c @@ -0,0 +1,34 @@ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "stdio.h" + +int +main(void) +{ + u2_init(); + + puts("\n>>> echo <<<"); + + while (1){ + int ch = getchar(); + putchar(ch); + } + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/eth_serdes.c b/firmware/microblaze/apps/cruft/eth_serdes.c new file mode 100644 index 000000000..2d2ddc1ca --- /dev/null +++ b/firmware/microblaze/apps/cruft/eth_serdes.c @@ -0,0 +1,233 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_passthru_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno __attribute__((unused)); // used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between ethernet and serdes + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // serdes -> eth (double buffer) +#define DSP_RX_BUF_1 3 // serdes -> eth +#define DSP_TX_BUF_0 4 // eth -> serdes (double buffer) +#define DSP_TX_BUF_1 5 // eth -> serdes + +/* + * ================================================================ + * configure serdes double buffering state machine (eth -> serdes) + * ================================================================ + */ + + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_tx_send_args = { + PORT_SERDES, + 0, + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ==================================================================== + * configure serdes RX double buffering state machine (serdes -> eth) + * ==================================================================== + */ + +// receive from serdes +buf_cmd_args_t dsp_rx_recv_args = { + PORT_SERDES, + 0, + BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// ---------------------------------------------------------------- + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY. This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet. A bit of a kludge + * but it should work. + */ + +bool +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false +{ +#if 0 + uint32_t *p = buffer_ram(buf_this); + uint32_t last_line = buffer_pool_status->last_line[buf_this] - sm->last_line_adj; + printf("fw_sets_seqno_inspector: buf_this = %d, last_line = %d\n", + buf_this, last_line); + + print_buffer(p, (last_line + 1)); +#endif + +#if 0 + uint32_t *p = buffer_ram(buf_this); + uint32_t seqno = fw_seqno++; + + // KLUDGE all kinds of nasty magic numbers and embedded knowledge + uint32_t t = p[4]; + t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); + p[4] = t; +#endif + + return false; // we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + if (0 && (status & ~BPS_IDLE_ALL)){ + putstr("status = "); + puthex32_nl(status); + } + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ + u2_init(); + + output_regs->led_src = 0x3; // h/w controls bottom two bits + clocks_enable_test_clk(true, 1); + + putstr("\neth <-> serdes\n"); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + // clocks_mimo_config(MC_WE_LOCK_TO_SMA | MC_PROVIDE_CLK_TO_MIMO); + clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 1 + output_regs->debug_mux_ctrl = 1; + hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> serdes + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + // initialize double buffering state machine for serdes -> ethernet + + if (FW_SETS_SEQNO){ + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + } + else { + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + } + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; + + + // kick off the state machines + dbsm_start(&dsp_tx_sm); + dbsm_start(&dsp_rx_sm); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + } +} diff --git a/firmware/microblaze/apps/cruft/factory_test.c b/firmware/microblaze/apps/cruft/factory_test.c new file mode 100644 index 000000000..e1fbb0e40 --- /dev/null +++ b/firmware/microblaze/apps/cruft/factory_test.c @@ -0,0 +1,438 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <clocks.h> +#include "sd.h" + +#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno; // used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between ethernet and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + +/* + * ================================================================ + * configure DSP TX double buffering state machine (eth -> dsp) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ================================================================ + * configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int streaming_frame_count = 0; +#define FRAMES_PER_CMD 1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ + // setup RX DSP regs + dsp_rx_regs->clear_state = 1; // reset + + streaming_p = true; + streaming_frame_count = FRAMES_PER_CMD; + + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); // set "chain" bit + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + + dsp_rx_regs->rx_time = 0; // enqueue first of two commands + + // make sure this one and the rest have the "now" and "chain" bits set. + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); + + dsp_rx_regs->rx_time = 0; // enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ + host_mac_addr = *host; // remember who we're sending to + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, 0, 0); + // DSP RX will fill in timestamp + + memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + + if (FW_SETS_SEQNO) + fw_seqno = 0; + + streaming_items_per_frame = p->items_per_frame; + restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ + streaming_p = false; + dsp_rx_regs->clear_state = 1; // flush cmd queue + bp_clear_buf(DSP_RX_BUF_0); + bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 256; + int interp = 32; + + // setup some defaults + + dsp_tx_regs->freq = 0; + dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; + dsp_tx_regs->interp_rate = interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY. This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet. A bit of a kludge + * but it should work. + */ +bool +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false +{ + uint32_t *p = buffer_ram(buf_this); + uint32_t seqno = fw_seqno++; + + // KLUDGE all kinds of nasty magic numbers and embedded knowledge + uint32_t t = p[4]; + t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); + p[4] = t; + + // queue up another rx command when required + if (streaming_p && --streaming_frame_count == 0){ + streaming_frame_count = FRAMES_PER_CMD; + dsp_rx_regs->rx_time = 0; + } + + return false; // we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int test_ram() +{ + int i,j,k; + output_regs->ram_page = 1<<10; + + extram[0] = 0xDEADBEEF; + extram[1] = 0xF00D1234; + extram[7] = 0x76543210; + + output_regs->ram_page = 2<<10; + extram[7] = 0x55555555; + extram[1] = 0xaaaaaaaa; + extram[0] = 0xeeeeeeee; + + output_regs->ram_page = 1<<10; + + i = extram[0]; + k = extram[1]; + j = extram[7]; + + if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { + puts("RAM FAIL1!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + + output_regs->ram_page = 2<<10; + + j = extram[7]; + k = extram[1]; + i = extram[0]; + + if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { + puts("RAM FAIL2!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + return 1; +} + +int test_sd() +{ + int i = sd_init(); + if(i==0) { + puts("FAILED INIT of Card\n"); + return 0; + } + + unsigned char buf[512]; + i = sd_read_block(2048,buf); + if(i == 0) { + puts("READ Command Rejected\n"); + return 0; + } + if((buf[0]==0xb8)&&(buf[1]==0x08)&&(buf[2]==0x00)&&(buf[3]==0x50)) + ; + else { + puts("Read bad data from SD Card\n"); + return 0; + } + return 1; +} + +int +main(void) +{ + u2_init(); + + putstr("\nFactory Test\n"); + + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + + if(test_sd()) + puts("SD OK\n"); + else { + puts("SD FAIL\n"); + // hal_finish(); + //return 0; + } + if(test_ram()) + puts("RAM OK\n"); + else { + puts("RAM FAIL\n"); + hal_finish(); + return 0; + } + + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + + output_regs->led_src = 0x7; // make bottom 3 controlled by HW + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + clocks_enable_tx_dboard(true,1); + clocks_mimo_config(MC_WE_LOCK_TO_SMA); +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + + output_regs->debug_mux_ctrl = 1; +#if 0 + hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + // initialize double buffering state machine for DSP RX -> Ethernet + + if (FW_SETS_SEQNO){ + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + } + else { + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + } + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; + + + // program tx registers + setup_tx(); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + if (streaming_p){ + // restart_streaming(); + // FIXME report error + } + else { + // FIXME report error + } + putchar('O'); + } + } +} diff --git a/firmware/microblaze/apps/cruft/gen_eth_packets.c b/firmware/microblaze/apps/cruft/gen_eth_packets.c new file mode 100644 index 000000000..4d521f6bf --- /dev/null +++ b/firmware/microblaze/apps/cruft/gen_eth_packets.c @@ -0,0 +1,187 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include "print_rmon_regs.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +// ---------------------------------------------------------------- + +static eth_mac_addr_t dst_mac_addr = + {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; + +// ---------------------------------------------------------------- + +// #define PACKET_SIZE 1500 // bytes +// #define ETH_DATA_RATE 1000000 // 1MB/s +// #define ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE) // 13,3333 pkts/s + +// static int timer_delta = MASTER_CLK_RATE/ETH_PACKET_RATE; // ticks between interrupts + +static int timer_delta = (int)(MASTER_CLK_RATE * 1e-3); // tick at 1 kHz +static int sim_timer_delta = (int)(MASTER_CLK_RATE * 100e-6); // tick at 10 kHz + +static volatile bool send_packet_now = false; // timer handler sets this +static volatile bool link_is_up = false; // eth handler sets this + +int packet_number = 0; + + +#define CPU_TX_BUF 0 // cpu xmits ethernet frames from here +#define CPU_RX_BUF 1 // receive ethernet frames here + +// ---------------------------------------------------------------- + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + link_is_up = speed == 0 ? false : true; + hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2); + printf("\neth link changed: speed = %d\n", speed); +} + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout + send_packet_now = 1; +} + + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ + int i = 0; + int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + + for (i = 0; i < BP_NLINES; i++){ + buf[i] = mark | i; + mark ^= 0x00FF0000; + } + + // copy header into buffer + memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ + u2_eth_packet_t pkt __attribute__((aligned (4))); + + memset(&pkt, 0, sizeof(pkt)); + + pkt.ehdr.dst = dst_mac_addr; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + pkt.fixed.word0 = 0x01234567; + pkt.fixed.timestamp = 0xffffffff; + + // init just the one we're using + init_packet((void *)buffer_ram(CPU_TX_BUF), &pkt, CPU_TX_BUF); +} + +int +main(void) +{ + int npackets_sent = 0; + + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\ngen_eth_packets\n"); + + hal_set_leds(0x0, 0x3); + + init_packets(); + + pic_register_handler(IRQ_TIMER, timer_irq_handler); + + if (hwconfig_simulation_p()) + timer_delta = sim_timer_delta; + + hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + /* + if (hwconfig_simulation_p()){ + eth_mac->speed = 4; // hardcode mac speed to 1000 + link_is_up = true; + } + */ + + // fire off a receive from the ethernet + bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); + + while(1){ + uint32_t status = buffer_pool_status->status; + + if (status & (BPS_DONE(CPU_RX_BUF) | BPS_ERROR(CPU_RX_BUF))){ + bp_clear_buf(CPU_RX_BUF); + // ignore incoming ethernet packets; they were looped back in sim + bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); + } + + if (status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))){ + if (status & BPS_ERROR(CPU_TX_BUF)){ + putchar('E'); + } + bp_clear_buf(CPU_TX_BUF); + npackets_sent++; + if ((npackets_sent & 0xF) == 0){ // print after every 16 packets + //print_rmon_regs(); + putchar('.'); + } + } + + if (link_is_up && send_packet_now && (status & BPS_IDLE(CPU_TX_BUF))){ + send_packet_now = false; + + // kick off the next packet + // FIXME set packet number in packet + + bp_send_from_buf(CPU_TX_BUF, PORT_ETH, 1, 0, 255); // 1KB total + hal_toggle_leds(0x1); + } + } + + hal_finish(); + return 1; +} diff --git a/firmware/microblaze/apps/cruft/gen_pause_frames.c b/firmware/microblaze/apps/cruft/gen_pause_frames.c new file mode 100644 index 000000000..0f81dafff --- /dev/null +++ b/firmware/microblaze/apps/cruft/gen_pause_frames.c @@ -0,0 +1,207 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "u2_eth_packet.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> + + +// ---------------------------------------------------------------- + +unsigned char dst_mac_addr[6] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +// ---------------------------------------------------------------- + +// #define PACKET_SIZE 1500 // bytes +// #define ETH_DATA_RATE 1000000 // 1MB/s +// #define ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE) // 13,3333 pkts/s + +// static int timer_delta = MASTER_CLK_RATE/ETH_PACKET_RATE; // ticks between interrupts + +static int timer_delta = MASTER_CLK_RATE/1000; // tick at 1kHz + +static volatile bool send_packet_now = false; // timer handler sets this +static volatile bool link_is_up = false; // eth handler sets this + +int packet_number = 0; + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK 0xE0000 +#define LS_1000 0x80000 +#define LS_100 0x40000 +#define LS_10 0x20000 + + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + int v = 0; + switch(speed){ + case 10: + v = LS_10; + link_is_up = true; + break; + + case 100: + v = LS_100; + link_is_up = true; + break; + + case 1000: + v = LS_100; + link_is_up = true; + break; + + default: + v = 0; + link_is_up = false; + break; + } + + hal_gpio_set_tx(v, LS_MASK); /* set debug bits on d'board */ + + putstr("\neth link changed: speed = "); + puthex16_nl(speed); +} + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout + send_packet_now = 1; +} + + +void +buffer_irq_handler(unsigned irq) +{ + // FIXME +} + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ + int i = 0; + int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + + for (i = 0; i < BP_NLINES; i++){ + buf[i] = mark | i; + mark ^= 0x00FF0000; + } + + // copy header into buffer + memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ + int i; + + u2_eth_packet_t pkt __attribute__((aligned (4))); + + for (i = 0; i < 6; i++){ + pkt.ehdr.dst.addr[i] = dst_mac_addr[i]; + } + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + + // fill ALL buffers for debugging + for (i = 0; i < 8; i++) + init_packet((void *)buffer_ram(i), &pkt, i); +} + +static int led_counter = 0; + +int +main(void) +{ + int send_pause = 1; + + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\ngen_eth_packets\n"); + + // Control LEDs + output_regs->leds = 0x00; + + init_packets(); + + // pic_register_handler(IRQ_BUFFER, buffer_irq_handler); // poll for now + pic_register_handler(IRQ_TIMER, timer_irq_handler); + hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + + ethernet_init(); + + eth_mac->pause_frame_send_en = 1; + eth_mac->pause_quanta_set = 16384 / 512; + + // eth_mac->speed = 4; // FIXME hardcode mac speed to 1000 + + while(1){ + if (link_is_up && send_packet_now){ + send_packet_now = false; + + + if (send_pause) + eth_mac->xon_cpu = 1; + else + eth_mac->xon_cpu = 0; + + send_pause ^= 1; + + // kick off the next packet + // FIXME set packet number in packet + +#if 0 + bp_send_from_buf(0, PORT_ETH, 1, 0, 255); // 1KB total + + while ((buffer_pool_status->status & (BPS_DONE_0|BPS_ERROR_0)) == 0) + ; + bp_clear_buf(0); +#endif + + output_regs->leds = ((++led_counter) & 0x1) | (link_is_up ? 0x2 : 0x0); + } + } + + hal_finish(); + return 1; +} diff --git a/firmware/microblaze/apps/cruft/hello.c b/firmware/microblaze/apps/cruft/hello.c new file mode 100644 index 000000000..bce843093 --- /dev/null +++ b/firmware/microblaze/apps/cruft/hello.c @@ -0,0 +1,30 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "stdio.h" + +int +main(void) +{ + u2_init(); + + puts("Hello World"); + puts("Goodbye World"); + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/ibs_rx_test.c b/firmware/microblaze/apps/cruft/ibs_rx_test.c new file mode 100644 index 000000000..bdc04747e --- /dev/null +++ b/firmware/microblaze/apps/cruft/ibs_rx_test.c @@ -0,0 +1,82 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "nonstdio.h" + +#define PORT 2 // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + +static void __attribute__((unused)) +wait_until_status_nonzero(void) +{ + while (buffer_pool_status->status == 0) + ; +} + +int +main(void) +{ + int i; + + u2_init(); + + output_regs->adc_ctrl = 0x0A; + + dsp_rx_regs->freq = 0; + dsp_rx_regs->scale_iq = (1 << 16) | 1; + dsp_rx_regs->decim_rate = 8; + + volatile unsigned int *buffer0 = buffer_ram(0); + volatile unsigned int *buffer1 = buffer_ram(1); + volatile unsigned int *buffer2 = buffer_ram(2); + + putstr("Starting RX\n"); + bp_clear_buf(0); + bp_receive_to_buf(0, 1, 1, 0, 99); + + dsp_rx_regs->rx_command = (50 << 9) | 100; // Numlines, lines per frame + dsp_rx_regs->rx_time = 0x2000; + + dsp_rx_regs->rx_command = (137 << 9) | 50; // Numlines, lines per frame + dsp_rx_regs->rx_time = 0x2200; + + while (buffer_pool_status->status == 0) + ; + bp_clear_buf(0); + bp_clear_buf(1); + bp_receive_to_buf(1, 1, 1, 0, 99); + while (buffer_pool_status->status == 0) + ; + bp_clear_buf(2); + bp_receive_to_buf(2, 1, 1, 0, 99); + while (buffer_pool_status->status == 0) + ; + + for(i=0;i<100;i++) { + puthex(i); + putstr(" "); + puthex_nl(buffer0[i]); + } + for(i=0;i<60;i++) { + puthex(i); + putstr(" "); + puthex_nl(buffer1[i]); + } + for(i=0;i<60;i++) { + puthex(i); + putstr(" "); + puthex_nl(buffer2[i]); + } + //while(timer_regs -> time < 0x6000) + // {} + + putstr("Done\n"); + hal_finish(); + + return 1; +} diff --git a/firmware/microblaze/apps/cruft/ibs_tx_test.c b/firmware/microblaze/apps/cruft/ibs_tx_test.c new file mode 100644 index 000000000..ff9446d92 --- /dev/null +++ b/firmware/microblaze/apps/cruft/ibs_tx_test.c @@ -0,0 +1,160 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "nonstdio.h" + +// Globals +#define EMPTY 0 +#define FILLING 1 +#define FULL 2 +#define EMPTYING 3 + +#define PORT 2 // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + +static void +wait_until_status_nonzero(void) +{ + while (buffer_pool_status->status == 0) + ; +} + +int +main(void) +{ + int i; + + u2_init(); + + dsp_tx_regs->freq = 0; + dsp_tx_regs->scale_iq = (1 << 16) | 1; + dsp_tx_regs->interp_rate = 8; + + // Write data to be sent into the first buffer + volatile unsigned int *buffer0 = buffer_ram(0); + volatile unsigned int *buffer1 = buffer_ram(1); + + + putstr("Starting to fill in RAM\n"); + for(i=0;i<512;i++) + buffer0[i] = i; + putstr("Filled in RAM\n"); + + buffer0[0] = 7; // start and end of buffer, send immediately + buffer0[1] = 0x0000; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + while(timer_regs -> time < 0x6000) + {} + + buffer0[0] = 3; // start and end of buffer + buffer0[1] = 0x8000; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + while(timer_regs -> time < 0x8400) + {} + + buffer0[0] = 3; // start and end of buffer + buffer0[1] = 0x8800; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + while(timer_regs -> time < 0x9000) + {} + + buffer0[0] = 0x2; // not last + buffer0[1] = 0x9100; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + buffer0[0] = 0x1; // last + buffer0[1] = 0x0000; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + + + buffer0[0] = 0x3; // first and last + buffer0[1] = 0x8000; // Time in the past + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + + /* + buffer0[0] = 0x2; // not last + buffer0[1] = 0x9600; // start time + bp_clear_buf(0); + bp_send_from_buf(0, 1, 1, 0, 9); + while (buffer_pool_status->status == 0) + ; + */ + + while(timer_regs -> time < 0xa000) + {} + + putstr("Done\n"); + + while(1) + {} + hal_finish(); + + // Send a bunch, let them pile up in FIFO + bp_send_from_buf(0, 2, 1, 21, 80); wait_until_status_nonzero(); + bp_clear_buf(0); + putstr("First add'l TX done\n"); + bp_send_from_buf(0, 2, 1, 81, 288); wait_until_status_nonzero(); + bp_clear_buf(0); + bp_send_from_buf(0, 2, 1, 289, 292); wait_until_status_nonzero(); + bp_clear_buf(0); + bp_send_from_buf(0, 2, 1, 293, 326); wait_until_status_nonzero(); + bp_clear_buf(0); + bp_send_from_buf(0, 2, 1, 327, 399); wait_until_status_nonzero(); + bp_clear_buf(0); + bp_send_from_buf(0, 2, 1, 400, 511); wait_until_status_nonzero(); + bp_clear_buf(0); + putstr("All add'l TX done\n"); + + bp_receive_to_buf(1, 2, 1, 21, 80); wait_until_status_nonzero(); + bp_clear_buf(1); + putstr("First add'l RX done\n"); + bp_receive_to_buf(1, 2, 1, 81, 288); wait_until_status_nonzero(); + bp_clear_buf(1); + bp_receive_to_buf(1, 2, 1, 289, 292); wait_until_status_nonzero(); + bp_clear_buf(1); + bp_receive_to_buf(1, 2, 1, 293, 326); wait_until_status_nonzero(); + bp_clear_buf(1); + bp_receive_to_buf(1, 2, 1, 327, 399); wait_until_status_nonzero(); + bp_clear_buf(1); + bp_receive_to_buf(1, 2, 1, 400, 511); wait_until_status_nonzero(); + bp_clear_buf(1); + putstr("All add'l RX done\n"); + + for(i=0;i<512;i++) + if(buffer0[i] != buffer1[i]) { + putstr("ERROR at location: "); + puthex_nl(i); + putstr("Value sent: "); + puthex_nl(buffer0[i]); + putstr("Value rcvd: "); + puthex_nl(buffer1[i]); + //break; + } + + putstr("Done Testing\n"); + + hal_finish(); + return 1; +} diff --git a/firmware/microblaze/apps/cruft/mimo_app_common_v2.c b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c new file mode 100644 index 000000000..5dbecb0d0 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.c @@ -0,0 +1,582 @@ +/* -*- 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "mimo_app_common_v2.h" +#include "buffer_pool.h" +#include "memcpy_wa.h" +#include "ethernet.h" +#include "nonstdio.h" +#include "print_rmon_regs.h" +#include "db.h" +#include "db_base.h" +#include "clocks.h" +#include "u2_init.h" +#include <string.h> + +volatile bool link_is_up = false; // eth handler sets this +int cpu_tx_buf_dest_port = PORT_ETH; + +// If this is non-zero, this dbsm could be writing to the ethernet +dbsm_t *ac_could_be_sending_to_eth; + +static unsigned char exp_seqno __attribute__((unused)) = 0; + +void abort(void); + +static bool +burn_mac_addr(const op_burn_mac_addr_t *p) +{ + return ethernet_set_mac_addr(&p->addr); +} + +static bool +sync_to_pps(const op_generic_t *p) +{ + timesync_regs->sync_on_next_pps = 1; + putstr("SYNC to PPS\n"); + return true; +} + +static bool +config_mimo_cmd(const op_config_mimo_t *p) +{ + clocks_mimo_config(p->flags); + return true; +} + +void +set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt) +{ + reply_pkt->ehdr.dst = cmd_pkt->ehdr.src; + reply_pkt->ehdr.src = *ethernet_mac_addr(); + reply_pkt->ehdr.ethertype = U2_ETHERTYPE; + reply_pkt->thdr.flags = 0; + reply_pkt->thdr.fifo_status = 0; // written by protocol engine + reply_pkt->thdr.seqno = 0; // written by protocol engine + reply_pkt->thdr.ack = 0; // written by protocol engine + u2p_set_word0(&reply_pkt->fixed, 0, CONTROL_CHAN); + reply_pkt->fixed.timestamp = timer_regs->time; +} + +static void +send_reply(unsigned char *reply, size_t reply_len) +{ + if (reply_len < 64) + reply_len = 64; + + // wait for buffer to become idle + hal_set_leds(0x4, 0x4); + while((buffer_pool_status->status & BPS_IDLE(CPU_TX_BUF)) == 0) + ; + hal_set_leds(0x0, 0x4); + + // copy reply into CPU_TX_BUF + memcpy_wa(buffer_ram(CPU_TX_BUF), reply, reply_len); + + // wait until nobody else is sending to the ethernet + if (ac_could_be_sending_to_eth){ + hal_set_leds(0x8, 0x8); + dbsm_wait_for_opening(ac_could_be_sending_to_eth); + hal_set_leds(0x0, 0x8); + } + + if (0){ + printf("sending_reply to port %d, len = %d\n", cpu_tx_buf_dest_port, (int)reply_len); + print_buffer(buffer_ram(CPU_TX_BUF), reply_len/4); + } + + // fire it off + bp_send_from_buf(CPU_TX_BUF, cpu_tx_buf_dest_port, 1, 0, reply_len/4); + + // wait for it to complete (not long, it's a small pkt) + while((buffer_pool_status->status & (BPS_DONE(CPU_TX_BUF) | BPS_ERROR(CPU_TX_BUF))) == 0) + ; + + bp_clear_buf(CPU_TX_BUF); +} + + +static size_t +op_id_cmd(const op_generic_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_id_reply_t *r = (op_id_reply_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) // no room + return 0; + + // Build reply subpacket + + r->opcode = OP_ID_REPLY; + r->len = sizeof(op_id_reply_t); + r->rid = p->rid; + r->addr = *ethernet_mac_addr(); + r->hw_rev = (u2_hw_rev_major << 8) | u2_hw_rev_minor; + // r->fpga_md5sum = ; // FIXME + // r->sw_md5sum = ; // FIXME + + return r->len; +} + + +static size_t +config_tx_v2_cmd(const op_config_tx_v2_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_config_tx_reply_v2_t *r = (op_config_tx_reply_v2_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + struct tune_result tune_result; + memset(&tune_result, 0, sizeof(tune_result)); + + bool ok = true; + +#if 0 + if (p->valid & CFGV_GAIN){ + ok &= db_set_gain(tx_dboard, p->gain); + } + + if (p->valid & CFGV_FREQ){ + bool was_streaming = is_streaming(); + if (was_streaming) + stop_rx_cmd(); + + u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); + bool tune_ok = db_tune(tx_dboard, f, &tune_result); + ok &= tune_ok; + print_tune_result("Tx", tune_ok, f, &tune_result); + + if (was_streaming) + restart_streaming(); + } + + if (p->valid & CFGV_INTERP_DECIM){ + int interp = p->interp; + int hb1 = 0; + int hb2 = 0; + + if (!(interp & 1)){ + hb2 = 1; + interp = interp >> 1; + } + + if (!(interp & 1)){ + hb1 = 1; + interp = interp >> 1; + } + + if (interp < MIN_CIC_INTERP || interp > MAX_CIC_INTERP) + ok = false; + else { + dsp_tx_regs->interp_rate = (hb1<<9) | (hb2<<8) | interp; + // printf("Interp: %d, register %d\n", p->interp, (hb1<<9) | (hb2<<8) | interp); + } + } + + if (p->valid & CFGV_SCALE_IQ){ + dsp_tx_regs->scale_iq = p->scale_iq; + } +#endif + + // Build reply subpacket + + r->opcode = OP_CONFIG_TX_REPLY_V2; + r->len = sizeof(*r); + r->rid = p->rid; + r->ok = ok; + r->inverted = tune_result.inverted; + r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq); + r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq); + r->duc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq); + r->duc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq); + r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq); + r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq); + return r->len; +} + +static size_t +config_rx_v2_cmd(const op_config_rx_v2_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_config_rx_reply_v2_t *r = (op_config_rx_reply_v2_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + struct tune_result tune_result; + memset(&tune_result, 0, sizeof(tune_result)); + + bool ok = true; + + if (p->valid & CFGV_GAIN){ + ok &= db_set_gain(rx_dboard, p->gain); + } + + if (p->valid & CFGV_FREQ){ + bool was_streaming = is_streaming(); + if (was_streaming) + stop_rx_cmd(); + + u2_fxpt_freq_t f = u2_fxpt_freq_from_hilo(p->freq_hi, p->freq_lo); + bool tune_ok = db_tune(rx_dboard, f, &tune_result); + ok &= tune_ok; + print_tune_result("Rx", tune_ok, f, &tune_result); + + if (was_streaming) + restart_streaming(); + } + + if (p->valid & CFGV_INTERP_DECIM){ + int decim = p->decim; + int hb1 = 0; + int hb2 = 0; + + if(!(decim & 1)) { + hb2 = 1; + decim = decim >> 1; + } + + if(!(decim & 1)) { + hb1 = 1; + decim = decim >> 1; + } + + if (decim < MIN_CIC_DECIM || decim > MAX_CIC_DECIM) + ok = false; + else { + dsp_rx_regs->decim_rate = (hb1<<9) | (hb2<<8) | decim; + // printf("Decim: %d, register %d\n", p->decim, (hb1<<9) | (hb2<<8) | decim); + } + } + + if (p->valid & CFGV_SCALE_IQ){ + dsp_rx_regs->scale_iq = p->scale_iq; + } + + // Build reply subpacket + + r->opcode = OP_CONFIG_RX_REPLY_V2; + r->len = sizeof(*r); + r->rid = p->rid; + r->ok = ok; + r->inverted = tune_result.inverted; + r->baseband_freq_hi = u2_fxpt_freq_hi(tune_result.baseband_freq); + r->baseband_freq_lo = u2_fxpt_freq_lo(tune_result.baseband_freq); + r->ddc_freq_hi = u2_fxpt_freq_hi(tune_result.dxc_freq); + r->ddc_freq_lo = u2_fxpt_freq_lo(tune_result.dxc_freq); + r->residual_freq_hi = u2_fxpt_freq_hi(tune_result.residual_freq); + r->residual_freq_lo = u2_fxpt_freq_lo(tune_result.residual_freq); + + return r->len; +} + +static size_t +read_time_cmd(const op_generic_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_read_time_reply_t *r = (op_read_time_reply_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + r->opcode = OP_READ_TIME_REPLY; + r->len = sizeof(*r); + r->rid = p->rid; + r->time = timer_regs->time; + + return r->len; +} + +static void +fill_db_info(u2_db_info_t *p, const struct db_base *db) +{ + p->dbid = db->dbid; + p->freq_min_hi = u2_fxpt_freq_hi(db->freq_min); + p->freq_min_lo = u2_fxpt_freq_lo(db->freq_min); + p->freq_max_hi = u2_fxpt_freq_hi(db->freq_max); + p->freq_max_lo = u2_fxpt_freq_lo(db->freq_max); + p->gain_min = db->gain_min; + p->gain_max = db->gain_max; + p->gain_step_size = db->gain_step_size; +} + +static size_t +dboard_info_cmd(const op_generic_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_dboard_info_reply_t *r = (op_dboard_info_reply_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + r->opcode = OP_DBOARD_INFO_REPLY; + r->len = sizeof(*r); + r->rid = p->rid; + r->ok = true; + + fill_db_info(&r->tx_db_info, tx_dboard); + fill_db_info(&r->rx_db_info, rx_dboard); + + return r->len; +} + +static size_t +peek_cmd(const op_peek_t *p, + void *reply_payload, size_t reply_payload_space) +{ + op_generic_t *r = (op_generic_t *) reply_payload; + + putstr("peek: addr="); puthex32(p->addr); + printf(" bytes=%u\n", p->bytes); + + if ((reply_payload_space < (sizeof(*r) + p->bytes)) || + p->bytes > MAX_SUBPKT_LEN - sizeof(op_generic_t)) { + putstr("peek: insufficient reply packet space\n"); + return 0; // FIXME do partial read? + } + + r->opcode = OP_PEEK_REPLY; + r->len = sizeof(*r)+p->bytes; + r->rid = p->rid; + r->ok = true; + + memcpy_wa(reply_payload+sizeof(*r), (void *)p->addr, p->bytes); + + return r->len; +} + +static bool +poke_cmd(const op_poke_t *p) +{ + int bytes = p->len - sizeof(*p); + putstr("poke: addr="); puthex32(p->addr); + printf(" bytes=%u\n", bytes); + + uint8_t *src = (uint8_t *)p + sizeof(*p); + memcpy_wa((void *)p->addr, src, bytes); + + return true; +} + +static size_t +generic_reply(const op_generic_t *p, + void *reply_payload, size_t reply_payload_space, + bool ok) +{ + op_generic_t *r = (op_generic_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + r->opcode = p->opcode | OP_REPLY_BIT; + r->len = sizeof(*r); + r->rid = p->rid; + r->ok = ok; + + return r->len; +} + +static size_t +add_eop(void *reply_payload, size_t reply_payload_space) +{ + op_generic_t *r = (op_generic_t *) reply_payload; + if (reply_payload_space < sizeof(*r)) + return 0; // no room + + r->opcode = OP_EOP; + r->len = sizeof(*r); + r->rid = 0; + r->ok = 0; + + return r->len; +} + +void +handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len) +{ + unsigned char reply[sizeof(u2_eth_packet_t) + 4 * sizeof(u2_subpkt_t)] _AL4; + unsigned char *reply_payload = &reply[sizeof(u2_eth_packet_t)]; + int reply_payload_space = sizeof(reply) - sizeof(u2_eth_packet_t); + + // initialize reply + memset(reply, 0, sizeof(reply)); + set_reply_hdr((u2_eth_packet_t *) reply, pkt); + + // point to beginning of payload (subpackets) + unsigned char *payload = ((unsigned char *) pkt) + sizeof(u2_eth_packet_t); + int payload_len = len - sizeof(u2_eth_packet_t); + + size_t subpktlen = 0; + + while (payload_len >= sizeof(op_generic_t)){ + const op_generic_t *gp = (const op_generic_t *) payload; + subpktlen = 0; + + // printf("\nopcode = %d\n", gp->opcode); + + switch(gp->opcode){ + case OP_EOP: // end of subpackets + goto end_of_subpackets; + + case OP_ID: + subpktlen = op_id_cmd(gp, reply_payload, reply_payload_space); + break; + + case OP_CONFIG_TX_V2: + subpktlen = config_tx_v2_cmd((op_config_tx_v2_t *) payload, + reply_payload, reply_payload_space); + break; + + case OP_CONFIG_RX_V2: + subpktlen = config_rx_v2_cmd((op_config_rx_v2_t *) payload, + reply_payload, reply_payload_space); + break; + + case OP_START_RX_STREAMING: + start_rx_streaming_cmd(&pkt->ehdr.src, (op_start_rx_streaming_t *) payload); + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true); + break; + + case OP_STOP_RX: + stop_rx_cmd(); + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, true); + break; + + case OP_BURN_MAC_ADDR: + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, + burn_mac_addr((op_burn_mac_addr_t *) payload)); + break; + + case OP_CONFIG_MIMO: + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, + config_mimo_cmd((op_config_mimo_t *) payload)); + break; + + case OP_READ_TIME: + subpktlen = read_time_cmd(gp, reply_payload, reply_payload_space); + break; + + case OP_DBOARD_INFO: + subpktlen = dboard_info_cmd(gp, reply_payload, reply_payload_space); + break; + + case OP_SYNC_TO_PPS: + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, + sync_to_pps((op_generic_t *) payload)); + break; + + case OP_PEEK: + subpktlen = peek_cmd((op_peek_t *)payload, reply_payload, reply_payload_space); + break; + + case OP_POKE: + subpktlen = generic_reply(gp, reply_payload, reply_payload_space, + poke_cmd((op_poke_t *)payload)); + break; + + default: + printf("app_common_v2: unhandled opcode = %d\n", gp->opcode); + break; + } + + int t = (gp->len + 3) & ~3; // bump to a multiple of 4 + payload += t; + payload_len -= t; + + subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 + reply_payload += subpktlen; + reply_payload_space -= subpktlen; + } + + end_of_subpackets: + + // add the EOP marker + subpktlen = add_eop(reply_payload, reply_payload_space); + subpktlen = (subpktlen + 3) & ~3; // bump to a multiple of 4 + reply_payload += subpktlen; + reply_payload_space -= subpktlen; + + send_reply(reply, reply_payload - reply); +} + + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +int +eth_pkt_inspector(bsm12_t *sm, int bufno) +{ + u2_eth_packet_t *pkt = (u2_eth_packet_t *) buffer_ram(bufno); + size_t byte_len = (buffer_pool_status->last_line[bufno] - 3) * 4; + + //static size_t last_len = 0; + + // hal_toggle_leds(0x1); + + // inspect rcvd frame and figure out what do do. + + if (pkt->ehdr.ethertype != U2_ETHERTYPE) + return true; // ignore, probably bogus PAUSE frame from MAC + + int chan = u2p_chan(&pkt->fixed); + + switch (chan){ + case CONTROL_CHAN: + handle_control_chan_frame(pkt, byte_len); + return -1; + break; + + case 0: + return 0; // pass it off to DSP TX + + case 1: + return 1; // pass it off to SERDES TX + + default: + abort(); + break; + } +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + link_is_up = speed != 0; + hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); + printf("\neth link changed: speed = %d\n", speed); +} + + +void +print_tune_result(char *msg, bool tune_ok, + u2_fxpt_freq_t target_freq, struct tune_result *r) +{ +#if 0 + printf("db_tune %s %s\n", msg, tune_ok ? "true" : "false"); + putstr(" target_freq "); print_fxpt_freq(target_freq); newline(); + putstr(" baseband_freq "); print_fxpt_freq(r->baseband_freq); newline(); + putstr(" dxc_freq "); print_fxpt_freq(r->dxc_freq); newline(); + putstr(" residual_freq "); print_fxpt_freq(r->residual_freq); newline(); + printf(" inverted %s\n", r->inverted ? "true" : "false"); +#endif +} diff --git a/firmware/microblaze/apps/cruft/mimo_app_common_v2.h b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h new file mode 100644 index 000000000..1e62ced37 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_app_common_v2.h @@ -0,0 +1,63 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_APP_COMMON_H +#define INCLUDED_APP_COMMON_H + +#include <stdbool.h> +#include "usrp2_eth_packet.h" +#include "bsm12.h" +#include "memory_map.h" +#include "hal_io.h" +#include <stddef.h> +#include <db.h> + +#define CPU_TX_BUF 7 // cpu -> eth + +#define _AL4 __attribute__((aligned (4))) + +extern volatile bool link_is_up; // eth handler sets this + +// If there's a dbsm that sends to the ethernet, put it's address here +extern dbsm_t *ac_could_be_sending_to_eth; + +extern int cpu_tx_buf_dest_port; + +void set_reply_hdr(u2_eth_packet_t *reply_pkt, u2_eth_packet_t const *cmd_pkt); + +/* + * Called when an ethernet packet is received. + */ +int eth_pkt_inspector(bsm12_t *sm, int bufno); + + +void link_changed_callback(int speed); + +void +print_tune_result(char *msg, bool tune_ok, + u2_fxpt_freq_t target_freq, struct tune_result *r); + + +void start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p); +void stop_rx_cmd(void); +void restart_streaming(void); +bool is_streaming(void); + +void handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len); + +#endif /* INCLUDED_APP_COMMON_H */ diff --git a/firmware/microblaze/apps/cruft/mimo_tx.c b/firmware/microblaze/apps/cruft/mimo_tx.c new file mode 100644 index 000000000..e0f8aa6fa --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_tx.c @@ -0,0 +1,363 @@ +/* + * 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/>. + */ + +/* + * This is a down and dirty test program that confirms that the we can + * coherently transmit different signals to two USRP2s connected via a + * mimo cable. This code runs in the USRP2 connected to the ethernet. + * The other USRP runs mimo_tx_slave. The host runs test_mimo_tx. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "bsm12.h" +#include "mimo_app_common_v2.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "clocks.h" + +#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno; // used when f/w is filling in sequence numbers +#endif + + +/* + * Experimental code to transmit packets to DSP Tx and SERDES + * + * Hard wire the Tx config so we don't have to deal with control stuff yet. + */ + +#define BUF_BSM12_0 4 +#define BUF_BSM12_1 5 +#define BUF_BSM12_2 6 + +//#define CPU_TX_BUF 7 // cpu -> eth + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t bsm12_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t bsm12_send0_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +// send to SERDES +buf_cmd_args_t bsm12_send1_args = { + PORT_SERDES, + 0, // starts just past transport header + 0 // filled in from last_line register +}; + +bsm12_t bsm12_sm; // the state machine + +#if 0 +/* + * ================================================================ + * configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine +#endif + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int streaming_frame_count = 0; +#define FRAMES_PER_CMD 1000 + +bool is_streaming(void){ return streaming_p; } + + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ +#if 0 + // setup RX DSP regs + dsp_rx_regs->clear_state = 1; // reset + + streaming_p = true; + streaming_frame_count = FRAMES_PER_CMD; + + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); // set "chain" bit + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + + dsp_rx_regs->rx_time = 0; // enqueue first of two commands + + // make sure this one and the rest have the "now" and "chain" bits set. + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); + + dsp_rx_regs->rx_time = 0; // enqueue second command +#endif +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ +#if 0 + host_mac_addr = *host; // remember who we're sending to + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, 0, 0); + // DSP RX will fill in timestamp + + memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + + if (FW_SETS_SEQNO) + fw_seqno = 0; + + streaming_items_per_frame = p->items_per_frame; + restart_streaming(); +#endif +} + + +void +stop_rx_cmd(void) +{ +#if 0 + streaming_p = false; + dsp_rx_regs->clear_state = 1; // flush cmd queue + bp_clear_buf(DSP_RX_BUF_0); + bp_clear_buf(DSP_RX_BUF_1); +#endif +} + + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + + int tx_scale = 2500; + int interp = 8; // * 4 + + // setup some defaults + + dsp_tx_regs->freq = 429496730; // 10MHz + dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; + dsp_tx_regs->interp_rate = (1 << 9) | (1 << 8) | interp; +} + + +#if 0 +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY. This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet. A bit of a kludge + * but it should work. + */ +int +fw_sets_seqno_inspector(bsm12_t *sm, int buf_this) +{ + uint32_t *p = buffer_ram(buf_this); + uint32_t seqno = fw_seqno++; + + // KLUDGE all kinds of nasty magic numbers and embedded knowledge + uint32_t t = p[4]; + t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); + p[4] = t; + + // queue up another rx command when required + if (streaming_p && --streaming_frame_count == 0){ + streaming_frame_count = FRAMES_PER_CMD; + dsp_rx_regs->rx_time = 0; + } + + return false; // we didn't handle the packet +} +#endif +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + bsm12_process_status(&bsm12_sm, status); +} + +int +main(void) +{ + u2_init(); + + putstr("\nMIMO Tx\n"); + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + + output_regs->debug_mux_ctrl = 1; +#if 0 + hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> DSP Tx + + bsm12_init(&bsm12_sm, BUF_BSM12_0, + &bsm12_recv_args, &bsm12_send0_args, &bsm12_send1_args, + eth_pkt_inspector); + + +#if 0 + // initialize double buffering state machine for DSP RX -> Ethernet + + if (FW_SETS_SEQNO){ + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + } + else { + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + } + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; +#endif + + + // program tx registers + setup_tx(); + + // kick off the state machine + bsm12_start(&bsm12_sm); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + // dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + // dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + if (streaming_p){ + // restart_streaming(); + // FIXME report error + } + else { + // FIXME report error + } + putchar('O'); + } + } +} diff --git a/firmware/microblaze/apps/cruft/mimo_tx_slave.c b/firmware/microblaze/apps/cruft/mimo_tx_slave.c new file mode 100644 index 000000000..cdf9c03c2 --- /dev/null +++ b/firmware/microblaze/apps/cruft/mimo_tx_slave.c @@ -0,0 +1,376 @@ +/* + * 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/>. + */ + +/* + * This is a down and dirty test program that confirms that the we can + * coherently transmit different signals to two USRP2s connected via a + * mimo cable. This code runs in the USRP2 NOT connected to the + * ethernet. The USRP connected to the ethernet runs mimo_tx. The + * host runs test_mimo_tx. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno; // used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between serdes and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to serdes flow + * Buffers 4 and 5 are used to double-buffer the serdes to DSP Tx flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // dsp rx -> serdes (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> serdes +#define DSP_TX_BUF_0 4 // serdes -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // serdes -> dsp tx + +/* + * ================================================================== + * configure DSP TX double buffering state machine (serdes -> dsp) + * ================================================================== + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from serdes +buf_cmd_args_t dsp_tx_recv_args = { + PORT_SERDES, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ================================================================= + * configure DSP RX double buffering state machine (dsp -> serdes) + * ================================================================= + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_rx_send_args = { + PORT_SERDES, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int streaming_frame_count = 0; +#define FRAMES_PER_CMD 1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ + // setup RX DSP regs + dsp_rx_regs->clear_state = 1; // reset + + streaming_p = true; + streaming_frame_count = FRAMES_PER_CMD; + + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); // set "chain" bit + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + + dsp_rx_regs->rx_time = 0; // enqueue first of two commands + + // make sure this one and the rest have the "now" and "chain" bits set. + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); + + dsp_rx_regs->rx_time = 0; // enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ + host_mac_addr = *host; // remember who we're sending to + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, 0, 0); + // DSP RX will fill in timestamp + + memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + + if (FW_SETS_SEQNO) + fw_seqno = 0; + + streaming_items_per_frame = p->items_per_frame; + restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ + streaming_p = false; + dsp_rx_regs->clear_state = 1; // flush cmd queue + bp_clear_buf(DSP_RX_BUF_0); + bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 2500; + int interp = 8; // * 4 + + // setup some defaults + + dsp_tx_regs->freq = 429496730; // 10MHz + dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; + dsp_tx_regs->interp_rate = (1 << 9) | (1 << 8) | interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY. This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet. A bit of a kludge + * but it should work. + */ +bool +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false +{ + uint32_t *p = buffer_ram(buf_this); + uint32_t seqno = fw_seqno++; + + // KLUDGE all kinds of nasty magic numbers and embedded knowledge + uint32_t t = p[4]; + t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); + p[4] = t; + + // queue up another rx command when required + if (streaming_p && --streaming_frame_count == 0){ + streaming_frame_count = FRAMES_PER_CMD; + dsp_rx_regs->rx_time = 0; + } + + return false; // we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ + // hal_toggle_leds(LED_A); + + uint32_t status = buffer_pool_status->status; + + if (0 && (status & ~BPS_IDLE_ALL)){ + putstr("status = "); + puthex32_nl(status); + } + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ + u2_init(); + + output_regs->led_src = 0x3; // h/w controls bottom two bits + clocks_enable_test_clk(true, 1); + + putstr("\nMIMO Tx Slave\n"); + + cpu_tx_buf_dest_port = PORT_SERDES; + + // ethernet_register_link_changed_callback(link_changed_callback); + // ethernet_init(); + + clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + + // puts("post clocks_mimo_config"); + +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 0 + output_regs->debug_mux_ctrl = 1; + hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); + hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + //output_regs->flush_icache = 1; + + // initialize double buffering state machine for DSP RX -> Ethernet + + if (FW_SETS_SEQNO){ + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + } + else { + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + } + + // puts("post dbsm_init's"); + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; + + + // program tx registers + setup_tx(); + + // puts("post setup_tx"); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + // puts("post dbsm_start"); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + if (streaming_p){ + // restart_streaming(); + // FIXME report error + } + else { + // FIXME report error + } + putchar('O'); + } + } +} diff --git a/firmware/microblaze/apps/cruft/rcv_eth_packets.c b/firmware/microblaze/apps/cruft/rcv_eth_packets.c new file mode 100644 index 000000000..03fc94354 --- /dev/null +++ b/firmware/microblaze/apps/cruft/rcv_eth_packets.c @@ -0,0 +1,233 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> + + +// ---------------------------------------------------------------- + +static eth_mac_addr_t dst_mac_addr = + {{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}; + + +// ---------------------------------------------------------------- + +#define PACKET_SIZE 1500 // bytes +#define ETH_DATA_RATE 1000000 // 1MB/s +#define ETH_PACKET_RATE (ETH_DATA_RATE/PACKET_SIZE) // 13,3333 pkts/s + +#define TIMER_RATE 100000000 // 100 MHz clock + +static int timer_delta = TIMER_RATE/ETH_PACKET_RATE; // ticks between interrupts + +static volatile bool send_packet_now = false; // timer handler sets this +static volatile bool link_is_up = false; // eth handler sets this + +int packet_number = 0; + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK 0xE0000 +#define LS_1000 0x80000 +#define LS_100 0x40000 +#define LS_10 0x20000 + + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + int v = 0; + switch(speed){ + case 10: + v = LS_10; + link_is_up = true; + break; + + case 100: + v = LS_100; + link_is_up = true; + break; + + case 1000: + v = LS_100; + link_is_up = true; + break; + + default: + v = 0; + link_is_up = false; + break; + } + + //hal_gpio_set_tx(v, LS_MASK); /* set debug bits on d'board */ + + putstr("\neth link changed: speed = "); + puthex16_nl(speed); +} + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout + send_packet_now = 1; +} + + +void +buffer_irq_handler(unsigned irq) +{ + // FIXME +} + +static void +init_packet(int *buf, const u2_eth_packet_t *pkt, int bufnum) +{ + int i = 0; + int mark = ((bufnum & 0xff) << 24) | 0x005A0000; + + for (i = 0; i < BP_NLINES; i++){ + buf[i] = mark | i; + mark ^= 0x00FF0000; + } + + // copy header into buffer + memcpy_wa(buf, pkt, sizeof(*pkt)); +} + +static void +init_packets(void) +{ + int i; + + u2_eth_packet_t pkt __attribute__((aligned (4))); + + pkt.ehdr.dst = dst_mac_addr; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + + // fill ALL buffers for debugging + for (i = 0; i < 8; i++) + init_packet((void *)buffer_ram(i), &pkt, i); +} + +int +main(void) +{ + u2_init(); + + int prev_leds = -1; + int new_leds = 0x00; + output_regs->leds = 0x00; + + int peak_hold_count = 0; + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\nrcv_eth_packets\n"); + + init_packets(); + + // pic_register_handler(IRQ_BUFFER, buffer_irq_handler); // poll for now + + // FIXME turn off timer since I don't think MTS and MFS instructions are implemented + // pic_register_handler(IRQ_TIMER, timer_irq_handler); + // hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + + ethernet_init(); + + //eth_mac->speed = 4; // FIXME hardcode mac speed to 1000 + + // kick off a receive + bp_receive_to_buf(2, PORT_ETH, 1, 0, 511); + + while(1){ + // u2_eth_packet_t pkt; + + new_leds = 0; + if (link_is_up) + new_leds = 0x2; + + if ((buffer_pool_status->status & (BPS_DONE_2|BPS_ERROR_2)) != 0){ + // we've got a packet! + +#if 0 + // copy to stack buffer so we can byte address it + memcpy_wa(&pkt, (void *)buffer_ram(2), sizeof(pkt)); + + putstr("Rx: src: "); + print_mac_addr(pkt.ehdr.dst_addr); + putstr(" dst: "); + print_mac_addr(pkt.ehdr.src_addr); + putstr(" ethtype: "); + puthex16(pkt.ehdr.ethertype); + putstr(" len: "); + int len = (buffer_pool_status->last_line[2] + 1) * 4; + puthex16_nl(len); +#else + volatile int *bp = buffer_ram(2); + int i; + for (i = 0; i < 16; i++){ + puthex8(i); + putchar(':'); + puthex32_nl(bp[i]); + } +#endif + + // kick off next receive + bp_clear_buf(2); + bp_receive_to_buf(2, PORT_ETH, 1, 0, 511); + + peak_hold_count = 2048 * 10; + } + + if (peak_hold_count > 0){ + peak_hold_count--; + new_leds |= 0x1; + } + + if (new_leds != prev_leds){ + prev_leds = new_leds; + output_regs->leds = new_leds; + } + } + + hal_finish(); + return 1; +} diff --git a/firmware/microblaze/apps/cruft/read_dbids.c b/firmware/microblaze/apps/cruft/read_dbids.c new file mode 100644 index 000000000..24c6d9ab4 --- /dev/null +++ b/firmware/microblaze/apps/cruft/read_dbids.c @@ -0,0 +1,59 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <nonstdio.h> +#include <u2_init.h> +#include <stdbool.h> +#include <usrp2_i2c_addr.h> +#include <i2c.h> + + +int main(void) +{ + u2_init(); + + puts("\nread_dbids"); + + unsigned char dbid_tx[2]; + unsigned char dbid_rx[2]; + bool ok; + + ok = eeprom_read(I2C_ADDR_TX_A, 1, dbid_tx, 2); + if (!ok){ + puts("failed to read Tx Daugherboard EEPROM"); + } + else { + putstr("Tx Daugherboard ID: "); + puthex8(dbid_tx[1]); // MSB + puthex8(dbid_tx[0]); // LSB + newline(); + } + + ok = eeprom_read(I2C_ADDR_RX_A, 1, dbid_rx, 2); + if (!ok){ + puts("failed to read Rx Daugherboard EEPROM"); + } + else { + putstr("Rx Daugherboard ID: "); + puthex8(dbid_rx[1]); // MSB + puthex8(dbid_rx[0]); // LSB + newline(); + } + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/sd_bounce.c b/firmware/microblaze/apps/cruft/sd_bounce.c new file mode 100644 index 000000000..c1b48f170 --- /dev/null +++ b/firmware/microblaze/apps/cruft/sd_bounce.c @@ -0,0 +1,153 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * Loopback SERDES to SERDES + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "memset_wa.h" +#include <dbsm.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <clocks.h> + + + +// ---------------------------------------------------------------- + +#define SERDES_RX_BUF_0 0 +#define SERDES_RX_BUF_1 1 + +/* + * ================================================================ + * configure SD RX double buffering state machine + * ================================================================ + */ + +// receive from SERDES +buf_cmd_args_t sd_recv_args = { + PORT_SERDES, + 0, + BP_LAST_LINE +}; + +// send to SERDES +buf_cmd_args_t sd_send_args = { + PORT_SERDES, + 0, // starts with packet in line 0 + 0, // filled in from list_line register +}; + +dbsm_t sd_sm; // the state machine + + + + +// ---------------------------------------------------------------- + +#if 0 +static bool +check_packet(int *buf, int nlines) +{ + bool ok = true; + int i = 0; + for (i = 0; i < nlines; i++){ + int expected = ((2*i + 0) << 16) | (2*i+1); + if (buf[i] != expected){ + ok = false; + printf("buf[%d] = 0x%x expected = 0x%x\n", i, buf[i], expected); + } + } + return ok; +} + +static void +zero_buffer(int bufno) +{ + memset_wa(buffer_ram(bufno), 0, BP_NLINES * 4); +} +#endif + + +bool +sd_rx_inspector(dbsm_t *sm, int buf_this) +{ + hal_toggle_leds(0x2); + +#if 0 + int last_line = buffer_pool_status->last_line[buf_this]; + bool ok = check_packet(buffer_ram(buf_this), last_line); + static int good = 0; + static int bad = 0; + + if (ok) + good++; + else + bad++; + + if(good+bad == 10000) { + printf("Good %d\tBad %d\n",good,bad); + good = 0; + bad = 0; + } +#endif + + return false; +} + + +inline static void +buffer_irq_handler(void) +{ + uint32_t status = buffer_pool_status->status; + dbsm_process_status(&sd_sm, status); +} + + +int +main(void) +{ + u2_init(); + + putstr("\nsd_bounce\n"); + + // Get our clock from the mimo interface + clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + + dbsm_init(&sd_sm, SERDES_RX_BUF_0, + &sd_recv_args, &sd_send_args, + sd_rx_inspector); + + // kick off the state machine + dbsm_start(&sd_sm); + + while(1){ + buffer_irq_handler(); + } +} diff --git a/firmware/microblaze/apps/cruft/sd_gentest.c b/firmware/microblaze/apps/cruft/sd_gentest.c new file mode 100644 index 000000000..35e912615 --- /dev/null +++ b/firmware/microblaze/apps/cruft/sd_gentest.c @@ -0,0 +1,269 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "nonstdio.h" +#include "memset_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <clocks.h> +#include <mdelay.h> + +// ---------------------------------------------------------------- + +int packet_number = 0; +volatile bool send_packet_now = 0; + +#define SERDES_TX_BUF 0 +#define SERDES_RX_BUF 1 + + +#define NLINES_PER_PKT 380 + + +// ---------------------------------------------------------------- + +//static int timer_delta = (int)(MASTER_CLK_RATE * 100e-6); +static int timer_delta = 1000000; // .01 second + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout + send_packet_now = true; +} + + +static void +init_packet(int *buf) +{ + int i = 0; + for (i = 0; i < BP_NLINES; i++){ + buf[i] = ((2*i + 0) << 16) | (2*i+1); + } +} + +static bool +check_packet(int *buf, int nlines) +{ + bool ok = true; + int i = 0; + for (i = 0; i < nlines; i++){ + int expected = ((2*i + 0) << 16) | (2*i+1); + if (buf[i] != expected){ + ok = false; + printf("buf[%d] = 0x%x expected = 0x%x\n", i, buf[i], expected); + } + } + return ok; +} + +static void +zero_buffer(int bufno) +{ + memset_wa(buffer_ram(bufno), 0, BP_NLINES * 4); +} + +static void +init_packets(void) +{ + // init just the one we're using + init_packet(buffer_ram(SERDES_TX_BUF)); +} + +int +main(void) +{ + u2_init(); + + // We're free running and provide clock to the MIMO interface + clocks_mimo_config(MC_WE_DONT_LOCK | MC_PROVIDE_CLK_TO_MIMO); + + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + // output_regs->debug_mux_ctrl = 1; + // hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + // hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\nsd_gentest\n"); + + // Set up serdes (already enabled) + //output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN | SERDES_LOOPEN); + //output_regs->serdes_ctrl = (SERDES_ENABLE | SERDES_RXEN); + + init_packets(); + + // pic_register_handler(IRQ_TIMER, timer_irq_handler); + + //if (hwconfig_simulation_p()) + // timer_delta = sim_timer_delta; + + // start a receive from sd + zero_buffer(SERDES_RX_BUF); + bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); + + // fire off the first packet + bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); + hal_set_timeout(timer_delta); + int ready_to_send = 0; + + int counter __attribute__((unused)) = 0; + int sent = 1; + int txerr = 0; + int rxerr = 0; + int rcvd = 0; + int rxcrc = 0; + int sent_acc = 0; + int txerr_acc = 0; + int rxerr_acc = 0; + int rcvd_acc = 0; + int rxcrc_acc = 0; + +#define EXPECTING_PKT() ((counter & 0x1) == 0) +#define SEND_PKT() ((counter & 0x1) != 0) + + bool got_packet = false; + + while(1){ + uint32_t status = buffer_pool_status->status; + + if (status & (BPS_DONE(SERDES_RX_BUF))){ + bp_clear_buf(SERDES_RX_BUF); + got_packet = true; + + //hal_toggle_leds(0x2); + + // check packet + int last_line = buffer_pool_status->last_line[SERDES_RX_BUF]-1; + bool ok = check_packet(buffer_ram(SERDES_RX_BUF), last_line); + + if (ok) { + rcvd++; + //putchar('r'); + } + else { + rcvd++; + rxcrc++; + //putchar('P'); + } + // start a receive from sd + zero_buffer(SERDES_RX_BUF); + bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); + } + + if (status & (BPS_ERROR(SERDES_RX_BUF))){ + bp_clear_buf(SERDES_RX_BUF); + got_packet = true; + rcvd++; + rxerr++; + //putchar('E'); + + // start a receive from sd + zero_buffer(SERDES_RX_BUF); + bp_receive_to_buf(SERDES_RX_BUF, PORT_SERDES, 1, 0, BP_LAST_LINE); + } + + if (status & (BPS_DONE(SERDES_TX_BUF))){ + bp_clear_buf(SERDES_TX_BUF); + //putchar('t'); + bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); + //mdelay(1); + int i; + for (i = 0; i < 50; i++){ + asm volatile ("or r0, r0, r0\n\ + or r0, r0, r0\n \ + or r0, r0, r0\n \ + or r0, r0, r0\n \ + or r0, r0, r0\n \ + or r0, r0, r0\n \ + or r0, r0, r0\n"); + } + sent ++; + ready_to_send = 1; + //hal_toggle_leds(0x1); + } + + if (status & BPS_ERROR(SERDES_TX_BUF)){ + bp_clear_buf(SERDES_TX_BUF); + sent++; + txerr++; + ready_to_send = 1; + //putchar('X'); + } + + if(sent >=1000) { + printf("Status\tSENT %d\tTXERR %d\t",sent,txerr); + printf("RX %d\tERR %d\tCRC %d\tMISSED %d\n",rcvd, rxerr, rxcrc, sent-rcvd); + sent_acc += sent; sent = 0; + txerr_acc += txerr; txerr = 0; + rcvd_acc += rcvd; rcvd = 0; + rxerr_acc += rxerr; rxerr = 0; + rxcrc_acc += rxcrc; rxcrc = 0; + } + + if(sent_acc >=10000) { + printf("\nOverall\tSENT %d\tTXERR %d\t",sent_acc,txerr_acc); + printf("RX %d\tERR %d\tCRC %d\tMISSED %d\n\n",rcvd_acc, rxerr_acc, rxcrc_acc, sent_acc-rcvd_acc); + sent_acc = 0; + txerr_acc = 0; + rcvd_acc = 0; + rxerr_acc = 0; + rxcrc_acc = 0; + } +#if 0 + int pending = pic_regs->pending; + if (pending & PIC_TIMER_INT){ + hal_set_timeout(timer_delta); + + /* + if (EXPECTING_PKT()){ + if (!got_packet) + putchar('T'); + got_packet = false; + } + + if (SEND_PKT()){ + if (status & BPS_IDLE(SERDES_TX_BUF)) + bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); + } + counter++; + */ + + putchar('T'); + if(ready_to_send) { + bp_send_from_buf(SERDES_TX_BUF, PORT_SERDES, 1, 0, NLINES_PER_PKT); + counter++; + ready_to_send = 0; + } + + pic_regs->pending = PIC_TIMER_INT; // clear pending interrupt + } +#endif + } + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/serdes_to_dsp.c b/firmware/microblaze/apps/cruft/serdes_to_dsp.c new file mode 100644 index 000000000..4994e0a69 --- /dev/null +++ b/firmware/microblaze/apps/cruft/serdes_to_dsp.c @@ -0,0 +1,179 @@ +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu +//#define CPU_TX_BUF 1 // cpu -> eth + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + +/* + * ================================================================ + * configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_SERDES, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + + +// ---------------------------------------------------------------- + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void +start_rx_cmd(const eth_mac_addr_t *host, op_start_rx_t *p) +{ +} + +void +stop_rx_cmd(void) +{ +} + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 256; + int interp = 32; + + op_config_tx_t def_config; + memset(&def_config, 0, sizeof(def_config)); + def_config.phase_inc = 408021893; // 9.5 MHz [2**32 * fc/fsample] + def_config.scale_iq = (tx_scale << 16) | tx_scale; + def_config.interp = interp; + + // setup Tx DSP regs + config_tx_cmd(&def_config); +} + + +inline static void +buffer_irq_handler(unsigned irq) +{ + //hal_toggle_leds(0x2); + + uint32_t status = buffer_pool_status->status; + + dbsm_process_status(&dsp_tx_sm, status); + + if (status & BPS_DONE(CPU_TX_BUF)){ + bp_clear_buf(CPU_TX_BUF); + } +} + +int +main(void) +{ + u2_init(); + + // Get our clock from the mimo interface + + clocks_enable_test_clk(true,1); + clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\nserdes_to_dsp\n"); + + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + // program tx registers + setup_tx(); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + while(1){ + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + } +} + diff --git a/firmware/microblaze/apps/cruft/serdes_txrx.c b/firmware/microblaze/apps/cruft/serdes_txrx.c new file mode 100644 index 000000000..2c47c9628 --- /dev/null +++ b/firmware/microblaze/apps/cruft/serdes_txrx.c @@ -0,0 +1,368 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "dbsm.h" +#include "app_common_v2.h" +#include "memcpy_wa.h" +#include "clocks.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + + +#define FW_SETS_SEQNO 1 // define to 0 or 1 (FIXME must be 1 for now) + +#if (FW_SETS_SEQNO) +static int fw_seqno; // used when f/w is filling in sequence numbers +#endif + + +/* + * Full duplex Tx and Rx between serdes and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to serdes flow + * Buffers 4 and 5 are used to double-buffer the serdes to DSP Tx flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // dsp rx -> serdes (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> serdes +#define DSP_TX_BUF_0 4 // serdes -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // serdes -> dsp tx + +/* + * ================================================================== + * configure DSP TX double buffering state machine (serdes -> dsp) + * ================================================================== + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4) + +// Receive from serdes +buf_cmd_args_t dsp_tx_recv_args = { + PORT_SERDES, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ================================================================= + * configure DSP RX double buffering state machine (dsp -> serdes) + * ================================================================= + */ + +// 4 lines of ethernet hdr + 1 line transport hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE ((sizeof(u2_eth_hdr_t) + sizeof(u2_transport_hdr_t))/4 + 1) + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to serdes +buf_cmd_args_t dsp_rx_send_args = { + PORT_SERDES, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +// variables for streaming mode + +static bool streaming_p = false; +static unsigned int streaming_items_per_frame = 0; +static int streaming_frame_count = 0; +#define FRAMES_PER_CMD 1000 + +bool is_streaming(void){ return streaming_p; } + +// ---------------------------------------------------------------- + + +void +restart_streaming(void) +{ + // setup RX DSP regs + dsp_rx_regs->clear_state = 1; // reset + + streaming_p = true; + streaming_frame_count = FRAMES_PER_CMD; + + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); // set "chain" bit + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + + dsp_rx_regs->rx_time = 0; // enqueue first of two commands + + // make sure this one and the rest have the "now" and "chain" bits set. + dsp_rx_regs->rx_command = + MK_RX_CMD(FRAMES_PER_CMD * streaming_items_per_frame, + streaming_items_per_frame, + 1, 1); + + dsp_rx_regs->rx_time = 0; // enqueue second command +} + +void +start_rx_streaming_cmd(const eth_mac_addr_t *host, op_start_rx_streaming_t *p) +{ + host_mac_addr = *host; // remember who we're sending to + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, 0, 0); + // DSP RX will fill in timestamp + + memcpy_wa(buffer_ram(DSP_RX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_RX_BUF_1), &pkt, sizeof(pkt)); + + + if (FW_SETS_SEQNO) + fw_seqno = 0; + + streaming_items_per_frame = p->items_per_frame; + restart_streaming(); +} + + +void +stop_rx_cmd(void) +{ + streaming_p = false; + dsp_rx_regs->clear_state = 1; // flush cmd queue + bp_clear_buf(DSP_RX_BUF_0); + bp_clear_buf(DSP_RX_BUF_1); +} + + +static void +setup_tx() +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + int tx_scale = 256; + int interp = 32; + + // setup some defaults + + dsp_tx_regs->freq = 0; + dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; + dsp_tx_regs->interp_rate = interp; +} + + +#if (FW_SETS_SEQNO) +/* + * Debugging ONLY. This will be handled by the tx_protocol_engine. + * + * This is called when the DSP Rx chain has filled in a packet. + * We set and increment the seqno, then return false, indicating + * that we didn't handle the packet. A bit of a kludge + * but it should work. + */ +bool +fw_sets_seqno_inspector(dbsm_t *sm, int buf_this) // returns false +{ + uint32_t *p = buffer_ram(buf_this); + uint32_t seqno = fw_seqno++; + + // KLUDGE all kinds of nasty magic numbers and embedded knowledge + uint32_t t = p[4]; + t = (t & 0xffff00ff) | ((seqno & 0xff) << 8); + p[4] = t; + + // queue up another rx command when required + if (streaming_p && --streaming_frame_count == 0){ + streaming_frame_count = FRAMES_PER_CMD; + dsp_rx_regs->rx_time = 0; + } + + return false; // we didn't handle the packet +} +#endif + + +inline static void +buffer_irq_handler(unsigned irq) +{ + // hal_toggle_leds(LED_A); + + uint32_t status = buffer_pool_status->status; + + if (0 && (status & ~BPS_IDLE_ALL)){ + putstr("status = "); + puthex32_nl(status); + } + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ + u2_init(); + + output_regs->led_src = 0x3; // h/w controls bottom two bits + clocks_enable_test_clk(true, 1); + + putstr("\nSERDES TxRx\n"); + + cpu_tx_buf_dest_port = PORT_SERDES; + + // ethernet_register_link_changed_callback(link_changed_callback); + // ethernet_init(); + + clocks_mimo_config(MC_WE_LOCK_TO_MIMO); + + // puts("post clocks_mimo_config"); + +#if 0 + // make bit 15 of Tx gpio's be a s/w output + hal_gpio_set_sel(GPIO_TX_BANK, 15, 's'); + hal_gpio_set_ddr(GPIO_TX_BANK, 0x8000, 0x8000); +#endif + +#if 0 + output_regs->debug_mux_ctrl = 1; + hal_gpio_set_sels(GPIO_TX_BANK, "0000000000000000"); + hal_gpio_set_sels(GPIO_RX_BANK, "0000000000000000"); + hal_gpio_set_ddr(GPIO_TX_BANK, 0xffff, 0xffff); + hal_gpio_set_ddr(GPIO_RX_BANK, 0xffff, 0xffff); +#endif + + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + //output_regs->flush_icache = 1; + + // initialize double buffering state machine for DSP RX -> Ethernet + + if (FW_SETS_SEQNO){ + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + fw_sets_seqno_inspector); + } + else { + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + } + + // puts("post dbsm_init's"); + + // tell app_common that this dbsm could be sending to the ethernet + ac_could_be_sending_to_eth = &dsp_rx_sm; + + + // program tx registers + setup_tx(); + + // puts("post setup_tx"); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + // puts("post dbsm_start"); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + if (streaming_p){ + // restart_streaming(); + // FIXME report error + } + else { + // FIXME report error + } + putchar('O'); + } + } +} diff --git a/firmware/microblaze/apps/cruft/set_hw_rev.c b/firmware/microblaze/apps/cruft/set_hw_rev.c new file mode 100644 index 000000000..d4ac8ff81 --- /dev/null +++ b/firmware/microblaze/apps/cruft/set_hw_rev.c @@ -0,0 +1,45 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <u2_init.h> +#include <nonstdio.h> +#include <i2c.h> +#include <usrp2_i2c_addr.h> + +#define HW_REV_MAJOR 0 +#define HW_REV_MINOR 3 + +int +main(void) +{ + u2_init(); + + putstr("\nset_hw_rev\n"); + + bool ok = true; + unsigned char maj = HW_REV_MAJOR; + unsigned char min = HW_REV_MINOR; + ok = eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_MSB, &maj, 1); + ok &= eeprom_write(I2C_ADDR_MBOARD, MBOARD_REV_LSB, &min, 1); + + if (ok) + printf("OK: set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + else + printf("FAILED to set h/w rev to %d.%d\n", HW_REV_MAJOR, HW_REV_MINOR); + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/test1.c b/firmware/microblaze/apps/cruft/test1.c new file mode 100644 index 000000000..c3cc3be56 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test1.c @@ -0,0 +1,282 @@ +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include "nonstdio.h" + +// Globals +#define EMPTY 0 +#define FILLING 1 +#define FULL 2 +#define EMPTYING 3 + +#define PORT 2 // ethernet = 2, serdes = 0 +int dsp_rx_buf, dsp_tx_buf, serdes_rx_buf, serdes_tx_buf; +int dsp_rx_idle, dsp_tx_idle, serdes_rx_idle, serdes_tx_idle; + +int buffer_state[4]; + + +void double_buffering(int port); + +// +// We register this in the secondary interrupt vector. +// It's called on buffer manager interrupts +// +void +buffer_irq_handler(unsigned irq) +{ + double_buffering(PORT); +} + +int +main(void) +{ + int i; + + u2_init(); + + // Control LEDs + output_regs->leds = 0x02; + + // Turn on ADCs + output_regs->adc_ctrl = 0x0A; + + // Set up TX Chain + dsp_tx_regs->freq = 0; + dsp_tx_regs->scale_iq = (1 << 16) | 1; + dsp_tx_regs->interp_rate = 8; + + // Set up RX Chain + dsp_rx_regs->freq = 0; + dsp_rx_regs->scale_iq = (1 << 16) | 1; + dsp_rx_regs->decim_rate = 8; + + // Set up buffer control, using only 4 for now + for(i=0;i<4;i++) + buffer_state[i] = EMPTY; + + // Set up DSP RX + buffer_state[0] = FILLING; + serdes_tx_idle = 1; + bp_receive_to_buf(0, 1, 1, 10, 509); // DSP_RX to buffer 0, use 500 lines + + //dsp_rx_regs->run_rx = 1; // Start DSP_RX + putstr("Done DSP RX setup\n"); + + // Set up serdes RX + buffer_state[2] = FILLING; + dsp_tx_idle = 1; + bp_receive_to_buf(2, PORT, 1, 5, 504); + + while (buffer_pool_status->status == 0) // wait for completion of DSP RX + ; + + putstr("Done DSP TX setup\n"); + //dsp_tx_regs->run_tx = 1; + + // register interrupt handler + pic_register_handler(IRQ_BUFFER, buffer_irq_handler); + + while (1) + ; + + hal_finish(); + return 1; +} + +void +double_buffering(int port) { + unsigned int localstatus = buffer_pool_status->status; + + if(localstatus & BPS_DONE_0) { + bp_clear_buf(0); + if(buffer_state[0] == FILLING) { + buffer_state[0] = FULL; + if(buffer_state[1] == EMPTY) { + bp_receive_to_buf(1, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[1] = FILLING; + } + else + dsp_rx_idle = 1; + if(serdes_tx_idle) { + serdes_tx_idle = 0; + bp_send_from_buf(0, port, 1, 10, 509); // SERDES_TX from buffer 0 + buffer_state[0] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[0] = EMPTY; + if(dsp_rx_idle) { + dsp_rx_idle = 0; + bp_receive_to_buf(0, 1, 1, 10, 509); // DSP_RX to buffer 0, use 500 lines + buffer_state[0] = FILLING; + } + if(buffer_state[1] == FULL) { + bp_send_from_buf(1, port, 1, 10, 509); // SERDES_TX from buffer 1 + buffer_state[1] = EMPTYING; + } + else + serdes_tx_idle = 1; + } + putstr("Int Proc'ed 0\n"); + } + if(localstatus & BPS_DONE_1) { + bp_clear_buf(1); + if(buffer_state[1] == FILLING) { + buffer_state[1] = FULL; + if(buffer_state[0] == EMPTY) { + bp_receive_to_buf(0, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[0] = FILLING; + } + else + dsp_rx_idle = 1; + if(serdes_tx_idle) { + serdes_tx_idle = 0; + bp_send_from_buf(1, port, 1, 10, 509); // SERDES_TX from buffer 1 + buffer_state[1] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[1] = EMPTY; + if(dsp_rx_idle) { + dsp_rx_idle = 0; + bp_receive_to_buf(1, 1, 1, 10, 509); // DSP_RX to buffer 1, use 500 lines + buffer_state[1] = FILLING; + } + if(buffer_state[0] == FULL) { + bp_send_from_buf(0, port, 1, 10, 509); // SERDES_TX from buffer 0 + buffer_state[0] = EMPTYING; + } + else + serdes_tx_idle = 1; + } + putstr("Int Proc'ed 1\n"); + } + if(localstatus & BPS_DONE_2) { + bp_clear_buf(2); + if(buffer_state[2] == FILLING) { + buffer_state[2] = FULL; + if(buffer_state[3] == EMPTY) { + bp_receive_to_buf(3, port, 1, 5, 504); // SERDES_RX to buffer 3, use 500 lines + buffer_state[3] = FILLING; + } + else + serdes_rx_idle = 1; + if(dsp_tx_idle) { + dsp_tx_idle = 0; + bp_send_from_buf(2, 1, 1, 5, 504); // DSP_TX from buffer 2 + buffer_state[2] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[2] = EMPTY; + if(serdes_rx_idle) { + serdes_rx_idle = 0; + bp_receive_to_buf(2, port, 1, 5, 504); // SERDES_RX to buffer 2 + buffer_state[2] = FILLING; + } + if(buffer_state[3] == FULL) { + bp_send_from_buf(3, 1, 1, 5, 504); // DSP_TX from buffer 3 + buffer_state[3] = EMPTYING; + } + else + dsp_tx_idle = 1; + } + putstr("Int Proc'ed 2\n"); + } + if(localstatus & BPS_DONE_3) { + bp_clear_buf(3); + if(buffer_state[3] == FILLING) { + buffer_state[3] = FULL; + if(buffer_state[2] == EMPTY) { + bp_receive_to_buf(2, port, 1, 5, 504); // SERDES_RX to buffer 2, use 500 lines + buffer_state[2] = FILLING; + } + else + serdes_rx_idle = 1; + if(dsp_tx_idle) { + dsp_tx_idle = 0; + bp_send_from_buf(3, 1, 1, 5, 504); // DSP_TX from buffer 3 + buffer_state[3] = EMPTYING; + } + } + else { // buffer was emptying + buffer_state[3] = EMPTY; + if(serdes_rx_idle) { + serdes_rx_idle = 0; + bp_receive_to_buf(3, port, 1, 5, 504); // SERDES_RX to buffer 3 + buffer_state[3] = FILLING; + } + if(buffer_state[2] == FULL) { + bp_send_from_buf(2, 1, 1, 5, 504); // DSP_TX from buffer 2 + buffer_state[2] = EMPTYING; + } + else + dsp_tx_idle = 1; + } + putstr("Int Proc'ed 3\n"); + } +} + +// Spare Code + +#if 0 + // Set up LSDAC + int i = 0; + while(1) { + int command = (3 << 19) | (0 << 16) | (i & 0xffff); + spi_transact(SPI_TXONLY, SPI_SS_TX_DAC, command, 24, 1); // negate TX phase + i++; + } +#endif + +#if 0 + // Write to buffer 0 + int *buf = (int *)(BUFFER_BASE + BUFFER_0); + puthex_nl((int)buf); + + for(i=0;i<BUFFER_SIZE;i++) + buf[i] = i; + + putstr("Filled buffer 0\n"); + + // Write to buffer 1 + buf = (int *)(BUFFER_BASE + BUFFER_1); + puthex_nl((int)buf); + for(i=0;i<BUFFER_SIZE;i++) + buf[i] = i + ((i^0xFFFF) << 16); + + putstr("Filled buffer 1\n"); + +#endif + +#if 0 + // rx SERDES into buffer #2 (buf,port,step,fl,ll) + bp_receive_to_buf(2, 0, 1, 10, 300); + putstr("SERDES RX buffer setup\n"); + + // send SERDES from buffer #0 (buf,port,step,fl,ll) + bp_send_from_buf(0, 0, 1, 20, 200); + putstr("SERDES TX buffer setup\n"); + +#endif + +#if 0 + // send to DACs from buffer #1 + bp_send_from_buf(1 /*buf#*/, 1 /*port*/, 1 /*step*/, 20 /*fl*/, 250 /*ll*/); + putstr("DAC Buffer setup\n"); +#endif + +#if 0 + //putstr("ENTER INT\n"); + for(i=0;i<8;i++) + if(*status & (1<<i)) { + //putstr("Clearing buf "); + puthex_nl(i); + bp_clear_buf(i); + } + //putstr("EXIT INT\n"); +#endif diff --git a/firmware/microblaze/apps/cruft/test_db_spi.c b/firmware/microblaze/apps/cruft/test_db_spi.c new file mode 100644 index 000000000..f4fa98ef1 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_db_spi.c @@ -0,0 +1,35 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> +#include <spi.h> + +int +main(void) +{ + u2_init(); + + puts("\ntest_db_spi"); + + while(1){ + spi_transact(SPI_TXONLY, SPI_SS_RX_DB, 0xCC33, 16, SPIF_PUSH_FALL); + spi_transact(SPI_TXONLY, SPI_SS_TX_DB, 0x33CC, 16, SPIF_PUSH_FALL); + } +} diff --git a/firmware/microblaze/apps/cruft/test_i2c.c b/firmware/microblaze/apps/cruft/test_i2c.c new file mode 100644 index 000000000..f349ead88 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_i2c.c @@ -0,0 +1,108 @@ +/* + * 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 <stdio.h> +#include <stdint.h> +#include <u2_init.h> /* FIXME */ +#include <i2c.h> +#include <usrp2_i2c_addr.h> +#include <string.h> +#include <hal_io.h> + + + +#define ASSERT_TRUE(x) \ + do { \ + if (!(x)){ \ + printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + +#define ASSERT_FALSE(x) \ + do { \ + if (x){ \ + printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + + +#define BUFSIZE 128 + +int +main(void) +{ + int i; + bool ok; + int nerrors = 0; + uint8_t buf[BUFSIZE]; + int not_dev_addr = 0x35; // no device with this address on the i2c bus. + int offset; + int len; + + u2_init(); + + puts("test_i2c\n"); + + // try writing a non-existent device + buf[0] = 0xA5; + ok = i2c_write(not_dev_addr, buf, 1); + ASSERT_FALSE(ok); + + // try read from non-existent device + buf[0] = 0; + ok = i2c_read(not_dev_addr, buf, 1); + ASSERT_FALSE(ok); + + // try writing eeprom + offset = 31; + len = 8; + memset(buf, 0, sizeof(buf)); + for (i = 0; i < len; i++) + buf[i] = i; + ok = eeprom_write(I2C_ADDR_MBOARD, offset, buf, len); + ASSERT_TRUE(ok); + + // now try to read it back + offset = 31; + len = 8; + memset(buf, 0, sizeof(buf)); + ok = eeprom_read(I2C_ADDR_MBOARD, offset, buf, len); + ASSERT_TRUE(ok); + + // check result + for (i = 0; i < len; i++){ + if (buf[i] != i){ + printf("buf[%d] = %d, should be %d\n", i, buf[i], i); + nerrors++; + } + } + + if (nerrors == 0){ + output_regs->leds = 0x3; + puts("PASSED\n"); + } + else { + output_regs->leds = 0x0; + puts("FAILED\n"); + } + + hal_finish(); + return 0; +} + diff --git a/firmware/microblaze/apps/cruft/test_lsadc.c b/firmware/microblaze/apps/cruft/test_lsadc.c new file mode 100644 index 000000000..5fda29cd7 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_lsadc.c @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <lsadc.h> +#include <lsdac.h> +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> + +int +main(void) +{ + u2_init(); + + puts("\ntest_lsadc"); + + uint32_t r; + + unsigned int up_counter = 0; + + while (1){ + unsigned int v; + v = up_counter; + + lsdac_write_rx(0, v << 0); + lsdac_write_rx(2, v << 1); + +#if 1 + r = lsadc_read_rx(0); + lsdac_write_rx(1, r & 0x0fff); + //puthex32_nl(r); +#endif + +#if 1 + r = lsadc_read_rx(1); + lsdac_write_rx(3, r & 0x0fff); + //puthex32_nl(r); +#endif + + up_counter++; + } +} diff --git a/firmware/microblaze/apps/cruft/test_lsdac.c b/firmware/microblaze/apps/cruft/test_lsdac.c new file mode 100644 index 000000000..8c1bf333b --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_lsdac.c @@ -0,0 +1,51 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <lsdac.h> +#include <u2_init.h> +#include <nonstdio.h> +#include <hal_io.h> + +int +main(void) +{ + u2_init(); + + puts("\ntest_lsdac"); + + unsigned int up_counter = 0; + unsigned int dn_counter = 0; + + while(1){ + unsigned int v; + v = up_counter; + lsdac_write_rx(0, v << 0); + lsdac_write_rx(1, v << 1); + lsdac_write_rx(2, v << 2); + lsdac_write_rx(3, v << 3); + + v = up_counter; + lsdac_write_tx(0, v << 0); + lsdac_write_tx(1, v << 1); + lsdac_write_tx(2, v << 2); + lsdac_write_tx(3, v << 3); + + up_counter++; + dn_counter--; + } +} diff --git a/firmware/microblaze/apps/cruft/test_phy_comm.c b/firmware/microblaze/apps/cruft/test_phy_comm.c new file mode 100644 index 000000000..d312ca4cc --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_phy_comm.c @@ -0,0 +1,113 @@ +/* + * 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/>. + */ + +// check communication with ethernet PHY chip + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "ethernet.h" +#include "pic.h" +#include "nonstdio.h" + + +#define DELTA_T 12500000 // .125s (10ns per tick) +//#define DELTA_T 10000 + +// debugging output on tx pins +#define LS_MASK 0xE0000 +#define LS_1000 0x80000 +#define LS_100 0x40000 +#define LS_10 0x20000 + + + +#define U2_ETHERTYPE 0xBEEF + + +static volatile int led_link_up_flag = 0; + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + int v = 0; + switch(speed){ + case 10: + v = LS_10; + led_link_up_flag = 0x2; + break; + + case 100: + v = LS_100; + led_link_up_flag = 0x2; + break; + + case 1000: + v = LS_100; + led_link_up_flag = 0x2; + break; + + default: + v = 0; + led_link_up_flag = 0; + break; + } + + //hal_gpio_set_tx(v, LS_MASK); /* set debug bits on d'board */ + + putstr("\neth link changed: speed = "); + puthex_nl(speed); +} + +void +timer_handler(unsigned irq) +{ + static int led_counter = 0; + + hal_set_timeout(DELTA_T); // schedule next timeout + output_regs->leds = (led_counter++ & 0x1) | led_link_up_flag; +} + +int +main(void) +{ + u2_init(); + + putstr("\n test_phy_comm\n"); + + pic_register_handler(IRQ_ONETIME, timer_handler); + hal_set_timeout(DELTA_T); // schedule timeout + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + ethernet_register_link_changed_callback(link_changed_callback); + + output_regs->phy_ctrl = 1; /* reset the eth PHY */ + output_regs->phy_ctrl = 0; + + ethernet_init(); + + while(1) + ; + + return 0; +} diff --git a/firmware/microblaze/apps/cruft/test_ram.c b/firmware/microblaze/apps/cruft/test_ram.c new file mode 100644 index 000000000..77ee693f6 --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_ram.c @@ -0,0 +1,105 @@ +/* + * 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 <stdio.h> +#include <stdint.h> +#include <u2_init.h> /* FIXME */ +#include <sd.h> +#include <string.h> +#include <hal_io.h> +#include <nonstdio.h> +#include <hal_uart.h> + +#define ASSERT_TRUE(x) \ + do { \ + if (!(x)){ \ + printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + +#define ASSERT_FALSE(x) \ + do { \ + if (x){ \ + printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + + +#define BUFSIZE 128 + +int test_ram() +{ + int i,j,k; + output_regs->ram_page = 1<<10; + + extram[0] = 0xDEADBEEF; + extram[1] = 0xF00D1234; + extram[7] = 0x76543210; + + output_regs->ram_page = 2<<10; + extram[7] = 0x55555555; + extram[1] = 0xaaaaaaaa; + extram[0] = 0xeeeeeeee; + + output_regs->ram_page = 1<<10; + + i = extram[0]; + k = extram[1]; + j = extram[7]; + + if((i != 0xDEADBEEF)||(j!=0x76543210)||(k!=0xF00D1234)) { + puts("RAM FAIL1!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + + output_regs->ram_page = 2<<10; + + j = extram[7]; + k = extram[1]; + i = extram[0]; + + if((i != 0xeeeeeeee)||(j!=0x55555555)||(k!=0xaaaaaaaa)) { + puts("RAM FAIL2!\n"); + puthex32_nl(i); + puthex32_nl(j); + puthex32_nl(k); + return 0; + } + return 1; +} + +int +main(void) +{ + + u2_init(); + puts("\ntest_ram\n"); + int success = test_ram(); + if(success) + puts("RAM Passed Tests\n"); + else + puts("RAM Failed\n"); + + hal_finish(); + return 0; +} + diff --git a/firmware/microblaze/apps/cruft/test_sd.c b/firmware/microblaze/apps/cruft/test_sd.c new file mode 100644 index 000000000..494432d7f --- /dev/null +++ b/firmware/microblaze/apps/cruft/test_sd.c @@ -0,0 +1,81 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdint.h> +#include <u2_init.h> /* FIXME */ +#include <sd.h> +#include <string.h> +#include <hal_io.h> +#include <nonstdio.h> + + +#define ASSERT_TRUE(x) \ + do { \ + if (!(x)){ \ + printf("ASSERT_TRUE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + +#define ASSERT_FALSE(x) \ + do { \ + if (x){ \ + printf("ASSERT_FALSE failed on line %d\n", __LINE__); \ + nerrors++; \ + } \ + } while(0) + + +#define BUFSIZE 128 + +int +main(void) +{ + int i; + unsigned char buf[512]; + + u2_init(); + + puts("\ntest_sd\n"); + + + i = sd_init(); + if(i) + puts("Successfully Init'ed Card\n"); + else + puts("FAILED INIT of Card\n"); + + i = sd_read_block(2048,buf); + if(i) { + puts("READ Command accepted\n"); + for(i=0;i<512;i++) + if((i&15) == 15) + puthex8_nl(buf[i]); + else { + puthex8(buf[i]); + putchar(' '); + } + } + else + puts("READ Command Rejected\n"); + + puts("Done"); + hal_finish(); + return 0; +} + diff --git a/firmware/microblaze/apps/cruft/timer_test.c b/firmware/microblaze/apps/cruft/timer_test.c new file mode 100644 index 000000000..44e80b5f1 --- /dev/null +++ b/firmware/microblaze/apps/cruft/timer_test.c @@ -0,0 +1,57 @@ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "u2_init.h" +#include "memory_map.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include "nonstdio.h" +#include "hal_io.h" + +#define DELTA_T 500 // 5 us (10ns per tick) + + +void +timer_handler(unsigned irq) +{ + hal_set_timeout(DELTA_T); + + putstr("Tick: "); + puthex_nl(0); +} + +int +main(void) +{ + u2_init(); + + // setup timer + + putstr("Setting up timer\n"); + pic_register_handler(IRQ_ONETIME, timer_handler); + + hal_set_timeout(DELTA_T); + + while (1) + ; + + putstr("Done Testing\n"); + + hal_finish(); + return 1; +} diff --git a/firmware/microblaze/apps/cruft/tx_standalone.c b/firmware/microblaze/apps/cruft/tx_standalone.c new file mode 100644 index 000000000..1645fa8ba --- /dev/null +++ b/firmware/microblaze/apps/cruft/tx_standalone.c @@ -0,0 +1,339 @@ +/* + * 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/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "usrp2_eth_packet.h" +#include "memcpy_wa.h" +#include "dbsm.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#define _AL4 __attribute__((aligned (4))) + +#define USE_BUFFER_INTERRUPT 0 // 0 or 1 + + +static int timer_delta = MASTER_CLK_RATE/1000; // tick at 1kHz + +/* + * This program can respond to queries from the host + * and stream rx samples. + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu +#define CPU_TX_BUF 1 // cpu -> eth + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + + +/* + * ================================================================ + * configure DSP RX double buffering state machine + * ================================================================ + */ + + +// 4 lines of ethernet hdr + 1 line (word0) +// DSP Rx writes timestamp followed by nlines_per_frame of samples +#define DSP_RX_FIRST_LINE 5 +#define DSP_RX_SAMPLES_PER_FRAME 128 +#define DSP_RX_EXTRA_LINES 1 // writes timestamp + +// Receive from DSP Rx +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ethernet +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from last_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + +/* + * ================================================================ + * configure DSP TX double buffering state machine + * ================================================================ + */ + +// 4 lines of ethernet hdr + 2 lines (word0 + timestamp) +// DSP Tx reads word0 (flags) + timestamp followed by samples + +#define DSP_TX_FIRST_LINE 4 +#define DSP_TX_SAMPLES_PER_FRAME 250 // not used except w/ debugging +#define DSP_TX_EXTRA_LINES 2 // reads word0 + timestamp + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past ethernet header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * send constant buffer to DSP TX + */ +static inline void +SEND_CONST_TO_DSP_TX(void) +{ + bp_send_from_buf(DSP_TX_BUF_0, PORT_DSP, 1, + DSP_TX_FIRST_LINE, + DSP_TX_FIRST_LINE + DSP_TX_EXTRA_LINES + DSP_TX_SAMPLES_PER_FRAME - 1); +} + +// ---------------------------------------------------------------- + + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + + +void link_changed_callback(int speed); +static volatile bool link_is_up = false; // eth handler sets this + + +void +timer_irq_handler(unsigned irq) +{ + hal_set_timeout(timer_delta); // schedule next timeout +} + +// Tx DSP underrun +void +underrun_irq_handler(unsigned irq) +{ + dsp_tx_regs->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + dbsm_stop(&dsp_tx_sm); + + // FIXME anything else? + + putstr("\nirq: underrun\n"); +} + +// Rx DSP overrun +void +overrun_irq_handler(unsigned irq) +{ + dsp_rx_regs->clear_state = 1; + bp_clear_buf(DSP_RX_BUF_0); + bp_clear_buf(DSP_RX_BUF_1); + dbsm_stop(&dsp_rx_sm); + + // FIXME anything else? + + putstr("\nirq: overrun\n"); +} + +static void +start_tx_transfers(void) +{ + bp_clear_buf(DSP_TX_BUF_0); // FIXME, really goes in state machine + bp_clear_buf(DSP_TX_BUF_1); + + // fill everything with a constant 32k + 0j + + uint32_t const_sample = (32000 << 16) | 0; + int i; + for (i = 0; i < BP_NLINES; i++){ + buffer_ram(DSP_TX_BUF_0)[i] = const_sample; + buffer_ram(DSP_TX_BUF_1)[i] = const_sample; + } + + /* + * Construct ethernet header and word0 and preload into two buffers + */ + u2_eth_packet_t pkt; + memset(&pkt, 0, sizeof(pkt)); + //pkt.ehdr.dst = *host; + pkt.ehdr.src = *ethernet_mac_addr(); + pkt.ehdr.ethertype = U2_ETHERTYPE; + u2p_set_word0(&pkt.fixed, + U2P_TX_IMMEDIATE | U2P_TX_START_OF_BURST, 0); + u2p_set_timestamp(&pkt.fixed, T_NOW); + + memcpy_wa(buffer_ram(DSP_TX_BUF_0), &pkt, sizeof(pkt)); + memcpy_wa(buffer_ram(DSP_TX_BUF_1), &pkt, sizeof(pkt)); + + + int tx_scale = 256; + + // setup Tx DSP regs + dsp_tx_regs->clear_state = 1; // reset + dsp_tx_regs->freq = 408021893; // 9.5 MHz [2**32 * fc/fsample] + dsp_tx_regs->scale_iq = (tx_scale << 16) | tx_scale; + dsp_tx_regs->interp_rate = 32; + + // kick off the state machine + // dbsm_start(&dsp_rx_sm); + + SEND_CONST_TO_DSP_TX(); // send constant buffer to DSP TX +} + + +void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + if (0){ + putstr("irq: "); + puthex32(status); + putchar('\n'); + } + + if (status & BPS_ERROR_ALL){ + // FIXME rare path, handle error conditions + } + + if (status & BPS_DONE(DSP_TX_BUF_0)){ + bp_clear_buf(DSP_TX_BUF_0); + SEND_CONST_TO_DSP_TX(); + hal_toggle_leds(0x1); + } + +} + +int +main(void) +{ + u2_init(); + + // setup tx gpio bits for GPIOM_FPGA_1 -- fpga debug output + //hal_gpio_set_sels(GPIO_TX_BANK, "1111111111111111"); + //hal_gpio_set_sels(GPIO_RX_BANK, "1111111111111111"); + + putstr("\ntx_only\n"); + + // Control LEDs + hal_set_leds(0x0, 0x3); + + if (USE_BUFFER_INTERRUPT) + pic_register_handler(IRQ_BUFFER, buffer_irq_handler); + + pic_register_handler(IRQ_OVERRUN, overrun_irq_handler); + pic_register_handler(IRQ_UNDERRUN, underrun_irq_handler); + + //pic_register_handler(IRQ_TIMER, timer_irq_handler); + //hal_set_timeout(timer_delta); + + ethernet_register_link_changed_callback(link_changed_callback); + + ethernet_init(); + + // initialize double buffering state machine for DSP RX -> Ethernet + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_nop_inspector); + + // setup receive from ETH + // bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE); + +#if 0 + if (hwconfig_simulation_p()){ + // If we're simulating, pretend that we got a start command from the host + eth_mac_addr_t host = {{ 0x00, 0x0A, 0xE4, 0x3E, 0xD2, 0xD5 }}; + start_rx_cmd(&host); + } +#endif + + start_tx_transfers(); // send constant buffers to DSP TX + + while(1){ + if (!USE_BUFFER_INTERRUPT) + buffer_irq_handler(0); + } +} + +// ---------------------------------------------------------------- + +// debugging output on tx pins +#define LS_MASK 0xE0000 +#define LS_1000 0x80000 +#define LS_100 0x40000 +#define LS_10 0x20000 + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +void +link_changed_callback(int speed) +{ + int v = 0; + switch(speed){ + case 10: + v = LS_10; + link_is_up = true; + break; + + case 100: + v = LS_100; + link_is_up = true; + break; + + case 1000: + v = LS_100; + link_is_up = true; + break; + + default: + v = 0; + link_is_up = false; + break; + } + + //hal_gpio_set_tx(v, LS_MASK); /* set debug bits on d'board */ + + // hal_set_leds(link_is_up ? 0x2 : 0x0, 0x2); + + printf("\neth link changed: speed = %d\n", speed); +} 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 new file mode 100644 index 000000000..9c1873e1c --- /dev/null +++ b/firmware/microblaze/apps/txrx_uhd.c @@ -0,0 +1,587 @@ +// +// Copyright 2010 Ettus Research LLC +// +/* + * Copyright 2007,2008 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <lwip/ip.h> +#include <lwip/udp.h> +#include "u2_init.h" +#include "memory_map.h" +#include "spi.h" +#include "hal_io.h" +#include "buffer_pool.h" +#include "pic.h" +#include <stdbool.h> +#include "ethernet.h" +#include "nonstdio.h" +#include "dbsm.h" +#include <net/padded_eth_hdr.h> +#include <net_common.h> +#include "memcpy_wa.h" +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include "clocks.h" +#include "usrp2/fw_common.h" +#include <i2c_async.h> +#include <i2c.h> +#include <ethertype.h> +#include <arp_cache.h> +#include "udp_fw_update.h" + +/* + * Full duplex Tx and Rx between ethernet and DSP pipelines + * + * Buffer 1 is used by the cpu to send frames to the host. + * Buffers 2 and 3 are used to double-buffer the DSP Rx to eth flow + * Buffers 4 and 5 are used to double-buffer the eth to DSP Tx eth flow + */ +//#define CPU_RX_BUF 0 // eth -> cpu + +#define DSP_RX_BUF_0 2 // dsp rx -> eth (double buffer) +#define DSP_RX_BUF_1 3 // dsp rx -> eth +#define DSP_TX_BUF_0 4 // eth -> dsp tx (double buffer) +#define DSP_TX_BUF_1 5 // eth -> dsp tx + +/* + * ================================================================ + * configure DSP TX double buffering state machine (eth -> dsp) + * ================================================================ + */ + +// DSP Tx reads ethernet header words +#define DSP_TX_FIRST_LINE ((sizeof(padded_eth_hdr_t) + sizeof(struct ip_hdr) + sizeof(struct udp_hdr))/sizeof(uint32_t)) + +// Receive from ethernet +buf_cmd_args_t dsp_tx_recv_args = { + PORT_ETH, + 0, + BP_LAST_LINE +}; + +// send to DSP Tx +buf_cmd_args_t dsp_tx_send_args = { + PORT_DSP, + DSP_TX_FIRST_LINE, // starts just past transport header + 0 // filled in from last_line register +}; + +dbsm_t dsp_tx_sm; // the state machine + +/* + * ================================================================ + * configure DSP RX double buffering state machine (dsp -> eth) + * ================================================================ + */ + +static const uint32_t rx_ctrl_word = 1 << 16; + +// DSP Rx writes ethernet header words +#define DSP_RX_FIRST_LINE sizeof(rx_ctrl_word)/sizeof(uint32_t) + +static bool dbsm_rx_inspector(dbsm_t *sm, int buf_this){ + size_t num_lines = buffer_pool_status->last_line[buf_this]-DSP_RX_FIRST_LINE; + ((uint32_t*)buffer_ram(buf_this))[0] = (num_lines*sizeof(uint32_t)) | (1 << 16); + return false; +} + +// receive from DSP +buf_cmd_args_t dsp_rx_recv_args = { + PORT_DSP, + DSP_RX_FIRST_LINE, + BP_LAST_LINE +}; + +// send to ETH +buf_cmd_args_t dsp_rx_send_args = { + PORT_ETH, + 0, // starts with ethernet header in line 0 + 0, // filled in from list_line register +}; + +dbsm_t dsp_rx_sm; // the state machine + + +// The mac address of the host we're sending to. +eth_mac_addr_t host_mac_addr; + +static void setup_network(void); + +// ---------------------------------------------------------------- +// the fast-path setup global variables +// ---------------------------------------------------------------- +static eth_mac_addr_t fp_mac_addr_src, fp_mac_addr_dst; +static struct socket_address fp_socket_src, fp_socket_dst; + +// ---------------------------------------------------------------- +void start_rx_streaming_cmd(void); +void stop_rx_cmd(void); + +static void print_ip_addr(const void *t){ + uint8_t *p = (uint8_t *)t; + printf("%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +} + +void handle_udp_data_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //its a tiny payload, load the fast-path variables + fp_mac_addr_src = *ethernet_mac_addr(); + arp_cache_lookup_mac(&src.addr, &fp_mac_addr_dst); + fp_socket_src = dst; + fp_socket_dst = src; + printf("Storing for fast path:\n"); + printf(" source mac addr: "); + print_mac_addr(fp_mac_addr_src.addr); newline(); + printf(" source ip addr: "); + print_ip_addr(&fp_socket_src.addr); newline(); + printf(" source udp port: %d\n", fp_socket_src.port); + printf(" destination mac addr: "); + print_mac_addr(fp_mac_addr_dst.addr); newline(); + printf(" destination ip addr: "); + print_ip_addr(&fp_socket_dst.addr); newline(); + printf(" destination udp port: %d\n", fp_socket_dst.port); + newline(); + + //setup network and vrt + setup_network(); + + // kick off the state machine + dbsm_start(&dsp_rx_sm); + +} + +#define OTW_GPIO_BANK_TO_NUM(bank) \ + (((bank) == USRP2_DIR_RX)? (GPIO_RX_BANK) : (GPIO_TX_BANK)) + +//setup the output data +static usrp2_ctrl_data_t ctrl_data_out; +static struct socket_address i2c_src; +static struct socket_address spi_src; + +static volatile bool i2c_done = false; +void i2c_read_done_callback(void) { + //printf("I2C read done callback\n"); + i2c_async_data_ready(ctrl_data_out.data.i2c_args.data); + i2c_done = true; + i2c_register_callback(0); +} + +void i2c_write_done_callback(void) { + //printf("I2C write done callback\n"); + i2c_done = true; + i2c_register_callback(0); +} + +static volatile bool spi_done = false; +static volatile uint32_t spi_readback_data; +void get_spi_readback_data(void) { + ctrl_data_out.data.spi_args.data = spi_get_data(); + spi_done = true; + spi_register_callback(0); +} + +void handle_udp_ctrl_packet( + struct socket_address src, struct socket_address dst, + unsigned char *payload, int payload_len +){ + //printf("Got ctrl packet #words: %d\n", (int)payload_len); + const usrp2_ctrl_data_t *ctrl_data_in = (usrp2_ctrl_data_t *)payload; + uint32_t ctrl_data_in_id = ctrl_data_in->id; + + //ensure that the protocol versions match + if (payload_len >= sizeof(uint32_t) && ctrl_data_in->proto_ver != USRP2_FW_COMPAT_NUM){ + printf("!Error in control packet handler: Expected compatibility number %d, but got %d\n", + USRP2_FW_COMPAT_NUM, ctrl_data_in->proto_ver + ); + ctrl_data_in_id = USRP2_CTRL_ID_WAZZUP_BRO; + } + + //ensure that this is not a short packet + if (payload_len < sizeof(usrp2_ctrl_data_t)){ + printf("!Error in control packet handler: Expected payload length %d, but got %d\n", + (int)sizeof(usrp2_ctrl_data_t), payload_len + ); + ctrl_data_in_id = USRP2_CTRL_ID_HUH_WHAT; + } + + //setup the output data + ctrl_data_out.proto_ver = USRP2_FW_COMPAT_NUM; + ctrl_data_out.id=USRP2_CTRL_ID_HUH_WHAT; + ctrl_data_out.seq=ctrl_data_in->seq; + + //handle the data based on the id + switch(ctrl_data_in_id){ + + /******************************************************************* + * Addressing + ******************************************************************/ + case USRP2_CTRL_ID_WAZZUP_BRO: + ctrl_data_out.id = USRP2_CTRL_ID_WAZZUP_DUDE; + memcpy(&ctrl_data_out.data.ip_addr, get_ip_addr(), sizeof(struct ip_addr)); + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + break; + + /******************************************************************* + * SPI + ******************************************************************/ + case USRP2_CTRL_ID_TRANSACT_ME_SOME_SPI_BRO:{ + //transact + bool success = spi_async_transact( + //(ctrl_data_in->data.spi_args.readback == 0)? SPI_TXONLY : SPI_TXRX, + ctrl_data_in->data.spi_args.dev, //which device + ctrl_data_in->data.spi_args.data, //32 bit data + ctrl_data_in->data.spi_args.num_bits, //length in bits + (ctrl_data_in->data.spi_args.mosi_edge == USRP2_CLK_EDGE_RISE)? SPIF_PUSH_FALL : SPIF_PUSH_RISE | //flags + (ctrl_data_in->data.spi_args.miso_edge == USRP2_CLK_EDGE_RISE)? SPIF_LATCH_RISE : SPIF_LATCH_FALL, + get_spi_readback_data //callback + ); + + //load output + ctrl_data_out.id = USRP2_CTRL_ID_OMG_TRANSACTED_SPI_DUDE; + spi_src = src; + } +// send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + break; + + /******************************************************************* + * I2C + ******************************************************************/ + case USRP2_CTRL_ID_DO_AN_I2C_READ_FOR_ME_BRO:{ + uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; + i2c_register_callback(i2c_read_done_callback); + i2c_async_read( + ctrl_data_in->data.i2c_args.addr, + num_bytes + ); + i2c_src = src; +// i2c_dst = dst; + ctrl_data_out.id = USRP2_CTRL_ID_HERES_THE_I2C_DATA_DUDE; + ctrl_data_out.data.i2c_args.bytes = num_bytes; + } + break; + + case USRP2_CTRL_ID_WRITE_THESE_I2C_VALUES_BRO:{ + uint8_t num_bytes = ctrl_data_in->data.i2c_args.bytes; + i2c_register_callback(i2c_read_done_callback); + i2c_async_write( + ctrl_data_in->data.i2c_args.addr, + ctrl_data_in->data.i2c_args.data, + num_bytes + ); + i2c_src = src; +// i2c_dst = dst; + ctrl_data_out.id = USRP2_CTRL_ID_COOL_IM_DONE_I2C_WRITE_DUDE; + ctrl_data_out.data.i2c_args.bytes = num_bytes; + } + break; + + /******************************************************************* + * Peek and Poke Register + ******************************************************************/ + case USRP2_CTRL_ID_POKE_THIS_REGISTER_FOR_ME_BRO: + 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){ + case sizeof(uint64_t): + *((uint32_t *) ctrl_data_in->data.poke_args.addrhi) = (uint32_t)ctrl_data_in->data.poke_args.datahi; + //continue to uint32_t for low addr: + + case sizeof(uint32_t): + *((uint32_t *) ctrl_data_in->data.poke_args.addr) = (uint32_t)ctrl_data_in->data.poke_args.data; + break; + + case sizeof(uint16_t): + *((uint16_t *) ctrl_data_in->data.poke_args.addr) = (uint16_t)ctrl_data_in->data.poke_args.data; + break; + + case sizeof(uint8_t): + *((uint8_t *) ctrl_data_in->data.poke_args.addr) = (uint8_t)ctrl_data_in->data.poke_args.data; + break; + + } + ctrl_data_out.id = USRP2_CTRL_ID_OMG_POKED_REGISTER_SO_BAD_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + break; + + case USRP2_CTRL_ID_PEEK_AT_THIS_REGISTER_FOR_ME_BRO: + switch(ctrl_data_in->data.poke_args.num_bytes){ + case sizeof(uint64_t): + ctrl_data_out.data.poke_args.datahi = *((uint32_t *) ctrl_data_in->data.poke_args.addrhi); + //continue to uint32_t for low addr: + + case sizeof(uint32_t): + ctrl_data_out.data.poke_args.data = *((uint32_t *) ctrl_data_in->data.poke_args.addr); + break; + + case sizeof(uint16_t): + ctrl_data_out.data.poke_args.data = *((uint16_t *) ctrl_data_in->data.poke_args.addr); + break; + + case sizeof(uint8_t): + ctrl_data_out.data.poke_args.data = *((uint8_t *) ctrl_data_in->data.poke_args.addr); + break; + + } + ctrl_data_out.id = USRP2_CTRL_ID_WOAH_I_DEFINITELY_PEEKED_IT_DUDE; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + break; + + case USRP2_CTRL_ID_SO_LIKE_CAN_YOU_READ_THIS_UART_BRO:{ + //executes a readline()-style read, up to num_bytes long, up to and including newline + int num_bytes = ctrl_data_in->data.uart_args.bytes; + if(num_bytes > 20) num_bytes = 20; + num_bytes = fngets_timeout(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_out.data.uart_args.data, num_bytes); + ctrl_data_out.id = USRP2_CTRL_ID_I_HELLA_READ_THAT_UART_DUDE; + ctrl_data_out.data.uart_args.bytes = num_bytes; + break; + } + + case USRP2_CTRL_ID_HEY_WRITE_THIS_UART_FOR_ME_BRO:{ + int num_bytes = ctrl_data_in->data.uart_args.bytes; + if(num_bytes > 20) num_bytes = 20; + //before we write to the UART, we flush the receive buffer + //this assumes that we're interested in the reply + hal_uart_rx_flush(ctrl_data_in->data.uart_args.dev); + fnputstr(ctrl_data_in->data.uart_args.dev, (char *) ctrl_data_in->data.uart_args.data, num_bytes); + ctrl_data_out.id = USRP2_CTRL_ID_MAN_I_TOTALLY_WROTE_THAT_UART_DUDE; + ctrl_data_out.data.uart_args.bytes = num_bytes; + break; + } + + default: + ctrl_data_out.id = USRP2_CTRL_ID_HUH_WHAT; + send_udp_pkt(USRP2_UDP_CTRL_PORT, src, &ctrl_data_out, sizeof(ctrl_data_out)); + } + +} + +/* + * Called when an ethernet packet is received. + * Return true if we handled it here, otherwise + * it'll be passed on to the DSP Tx pipe + */ +static bool +eth_pkt_inspector(dbsm_t *sm, int bufno) +{ + //point me to the ethernet frame + uint32_t *buff = (uint32_t *)buffer_ram(bufno); + + //treat this as fast-path data? + // We have to do this operation as fast as possible. + // Therefore, we do not check all the headers, + // just check that the udp port matches + // and that the vrt header is non zero. + // In the future, a hardware state machine will do this... + if ( //warning! magic numbers approaching.... + (((buff + ((2 + 14 + 20)/sizeof(uint32_t)))[0] & 0xffff) == USRP2_UDP_DATA_PORT) && + ((buff + ((2 + 14 + 20 + 8)/sizeof(uint32_t)))[1] != USRP2_INVALID_VRT_HEADER) + ) return false; + + //test if its an ip recovery packet + typedef struct{ + padded_eth_hdr_t eth_hdr; + char code[4]; + union { + struct ip_addr ip_addr; + } data; + }recovery_packet_t; + recovery_packet_t *recovery_packet = (recovery_packet_t *)buff; + if (recovery_packet->eth_hdr.ethertype == 0xbeee && strncmp(recovery_packet->code, "addr", 4) == 0){ + printf("Got ip recovery packet: "); print_ip_addr(&recovery_packet->data.ip_addr); newline(); + set_ip_addr(&recovery_packet->data.ip_addr); + return true; + } + + //pass it to the slow-path handler + size_t len = buffer_pool_status->last_line[bufno] - 3; + handle_eth_packet(buff, len); + return true; +} + +//------------------------------------------------------------------ + +/* + * 1's complement sum for IP and UDP headers + * + * init chksum to zero to start. + */ +static unsigned int +CHKSUM(unsigned int x, unsigned int *chksum) +{ + *chksum += x; + *chksum = (*chksum & 0xffff) + (*chksum>>16); + *chksum = (*chksum & 0xffff) + (*chksum>>16); + return x; +} + +/* + * Called when eth phy state changes (w/ interrupts disabled) + */ +volatile bool link_is_up = false; // eth handler sets this +void +link_changed_callback(int speed) +{ + link_is_up = speed != 0; + hal_set_leds(link_is_up ? LED_RJ45 : 0x0, LED_RJ45); + printf("\neth link changed: speed = %d\n", speed); + if (link_is_up) send_gratuitous_arp(); +} + +static void setup_network(void){ + + //setup ethernet header machine + sr_udp_sm->eth_hdr.mac_dst_0_1 = (fp_mac_addr_dst.addr[0] << 8) | fp_mac_addr_dst.addr[1]; + sr_udp_sm->eth_hdr.mac_dst_2_3 = (fp_mac_addr_dst.addr[2] << 8) | fp_mac_addr_dst.addr[3]; + sr_udp_sm->eth_hdr.mac_dst_4_5 = (fp_mac_addr_dst.addr[4] << 8) | fp_mac_addr_dst.addr[5]; + sr_udp_sm->eth_hdr.mac_src_0_1 = (fp_mac_addr_src.addr[0] << 8) | fp_mac_addr_src.addr[1]; + sr_udp_sm->eth_hdr.mac_src_2_3 = (fp_mac_addr_src.addr[2] << 8) | fp_mac_addr_src.addr[3]; + sr_udp_sm->eth_hdr.mac_src_4_5 = (fp_mac_addr_src.addr[4] << 8) | fp_mac_addr_src.addr[5]; + sr_udp_sm->eth_hdr.ether_type = ETHERTYPE_IPV4; + + //setup ip header machine + unsigned int chksum = 0; + sr_udp_sm->ip_hdr.ver_ihl_tos = CHKSUM(0x4500, &chksum); // IPV4, 5 words of header (20 bytes), TOS=0 + sr_udp_sm->ip_hdr.total_length = UDP_SM_INS_IP_LEN; // Don't checksum this line in SW + sr_udp_sm->ip_hdr.identification = CHKSUM(0x0000, &chksum); // ID + sr_udp_sm->ip_hdr.flags_frag_off = CHKSUM(0x4000, &chksum); // don't fragment + sr_udp_sm->ip_hdr.ttl_proto = CHKSUM(0x2011, &chksum); // TTL=32, protocol = UDP (17 decimal) + //sr_udp_sm->ip_hdr.checksum .... filled in below + uint32_t src_ip_addr = fp_socket_src.addr.addr; + uint32_t dst_ip_addr = fp_socket_dst.addr.addr; + sr_udp_sm->ip_hdr.src_addr_high = CHKSUM(src_ip_addr >> 16, &chksum); // IP src high + sr_udp_sm->ip_hdr.src_addr_low = CHKSUM(src_ip_addr & 0xffff, &chksum); // IP src low + sr_udp_sm->ip_hdr.dst_addr_high = CHKSUM(dst_ip_addr >> 16, &chksum); // IP dst high + sr_udp_sm->ip_hdr.dst_addr_low = CHKSUM(dst_ip_addr & 0xffff, &chksum); // IP dst low + sr_udp_sm->ip_hdr.checksum = UDP_SM_INS_IP_HDR_CHKSUM | (chksum & 0xffff); + + //setup the udp header machine + sr_udp_sm->udp_hdr.src_port = fp_socket_src.port; + sr_udp_sm->udp_hdr.dst_port = fp_socket_dst.port; + sr_udp_sm->udp_hdr.length = UDP_SM_INS_UDP_LEN; + sr_udp_sm->udp_hdr.checksum = UDP_SM_LAST_WORD; // zero UDP checksum +} + +inline static void +buffer_irq_handler(unsigned irq) +{ + uint32_t status = buffer_pool_status->status; + + dbsm_process_status(&dsp_tx_sm, status); + dbsm_process_status(&dsp_rx_sm, status); +} + +int +main(void) +{ + u2_init(); + +//we do this to see if we should set a default ip addr or not +#ifdef USRP2P + bool safe_fw = find_safe_booted_flag(); + set_safe_booted_flag(0); + if(safe_fw) { + set_default_ip_addr(); + set_default_mac_addr(); + } +#endif + + putstr("\nTxRx-NEWETH\n"); + print_mac_addr(ethernet_mac_addr()->addr); + newline(); + print_ip_addr(get_ip_addr()); newline(); + printf("FPGA compatibility number: %d\n", USRP2_FPGA_COMPAT_NUM); + printf("Firmware compatibility number: %d\n", USRP2_FW_COMPAT_NUM); + + //1) register the addresses into the network stack + register_mac_addr(ethernet_mac_addr()); + register_ip_addr(get_ip_addr()); + + //2) register callbacks for udp ports we service + register_udp_listener(USRP2_UDP_CTRL_PORT, handle_udp_ctrl_packet); + register_udp_listener(USRP2_UDP_DATA_PORT, handle_udp_data_packet); + register_udp_listener(USRP2_UDP_UPDATE_PORT, handle_udp_fw_update_packet); + + //3) setup ethernet hardware to bring the link up + ethernet_register_link_changed_callback(link_changed_callback); + ethernet_init(); + + // initialize double buffering state machine for ethernet -> DSP Tx + + dbsm_init(&dsp_tx_sm, DSP_TX_BUF_0, + &dsp_tx_recv_args, &dsp_tx_send_args, + eth_pkt_inspector); + + + // initialize double buffering state machine for DSP RX -> Ethernet + + dbsm_init(&dsp_rx_sm, DSP_RX_BUF_0, + &dsp_rx_recv_args, &dsp_rx_send_args, + dbsm_rx_inspector); + + sr_tx_ctrl->clear_state = 1; + bp_clear_buf(DSP_TX_BUF_0); + bp_clear_buf(DSP_TX_BUF_1); + + // kick off the state machine + dbsm_start(&dsp_tx_sm); + + //int which = 0; + + while(1){ + // hal_gpio_write(GPIO_TX_BANK, which, 0x8000); + // which ^= 0x8000; + + buffer_irq_handler(0); + + if(i2c_done) { + i2c_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, i2c_src, &ctrl_data_out, sizeof(ctrl_data_out)); + //printf("Sending UDP packet from main loop for I2C...\n"); + } + + if(spi_done) { + spi_done = false; + send_udp_pkt(USRP2_UDP_CTRL_PORT, spi_src, &ctrl_data_out, sizeof(ctrl_data_out)); + } + + int pending = pic_regs->pending; // poll for under or overrun + + if (pending & PIC_UNDERRUN_INT){ + //dbsm_handle_tx_underrun(&dsp_tx_sm); + pic_regs->pending = PIC_UNDERRUN_INT; // clear interrupt + putchar('U'); + } + + if (pending & PIC_OVERRUN_INT){ + //dbsm_handle_rx_overrun(&dsp_rx_sm); + pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt + + // FIXME Figure out how to handle this robustly. + // Any buffers that are emptying should be allowed to drain... + + putchar('O'); + } + } +} 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; +} |