summaryrefslogtreecommitdiff
path: root/usrp2/firmware/apps
diff options
context:
space:
mode:
Diffstat (limited to 'usrp2/firmware/apps')
-rw-r--r--usrp2/firmware/apps/Makefile.am63
-rw-r--r--usrp2/firmware/apps/app_common_v2.c477
-rw-r--r--usrp2/firmware/apps/app_common_v2.h62
-rw-r--r--usrp2/firmware/apps/app_passthru_v2.c244
-rw-r--r--usrp2/firmware/apps/app_passthru_v2.h54
-rw-r--r--usrp2/firmware/apps/bitrot/tx_drop.c261
-rw-r--r--usrp2/firmware/apps/bitrot/tx_drop2.c292
-rw-r--r--usrp2/firmware/apps/bitrot/tx_drop_rate_limited.c233
-rw-r--r--usrp2/firmware/apps/blink_leds.c40
-rw-r--r--usrp2/firmware/apps/blink_leds2.c53
-rw-r--r--usrp2/firmware/apps/buf_ram_test.c89
-rw-r--r--usrp2/firmware/apps/can_i_sub.c25
-rw-r--r--usrp2/firmware/apps/double_buffer_fragment.c138
-rw-r--r--usrp2/firmware/apps/echo.c34
-rw-r--r--usrp2/firmware/apps/eth_serdes.c230
-rw-r--r--usrp2/firmware/apps/gen_eth_packets.c181
-rw-r--r--usrp2/firmware/apps/gen_pause_frames.c207
-rw-r--r--usrp2/firmware/apps/hello.c30
-rw-r--r--usrp2/firmware/apps/ibs_rx_test.c82
-rw-r--r--usrp2/firmware/apps/ibs_tx_test.c160
-rw-r--r--usrp2/firmware/apps/rcv_eth_packets.c233
-rw-r--r--usrp2/firmware/apps/read_dbids.c59
-rw-r--r--usrp2/firmware/apps/rx_only_v2.c263
-rw-r--r--usrp2/firmware/apps/sd_bounce.c153
-rw-r--r--usrp2/firmware/apps/sd_gentest.c269
-rw-r--r--usrp2/firmware/apps/serdes_to_dsp.c188
-rw-r--r--usrp2/firmware/apps/serdes_txrx.c346
-rw-r--r--usrp2/firmware/apps/test1.c282
-rw-r--r--usrp2/firmware/apps/test_db_spi.c35
-rw-r--r--usrp2/firmware/apps/test_i2c.c108
-rw-r--r--usrp2/firmware/apps/test_lsadc.c57
-rw-r--r--usrp2/firmware/apps/test_lsdac.c51
-rw-r--r--usrp2/firmware/apps/test_phy_comm.c113
-rw-r--r--usrp2/firmware/apps/test_serdes.c192
-rw-r--r--usrp2/firmware/apps/timer_test.c59
-rw-r--r--usrp2/firmware/apps/tx_only_v2.c171
-rw-r--r--usrp2/firmware/apps/tx_standalone.c338
-rw-r--r--usrp2/firmware/apps/txrx.c344
38 files changed, 6216 insertions, 0 deletions
diff --git a/usrp2/firmware/apps/Makefile.am b/usrp2/firmware/apps/Makefile.am
new file mode 100644
index 000000000..092dd9441
--- /dev/null
+++ b/usrp2/firmware/apps/Makefile.am
@@ -0,0 +1,63 @@
+#
+# 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 = ../lib/libu2fw.a
+
+noinst_PROGRAMS = \
+ blink_leds \
+ blink_leds2 \
+ buf_ram_test \
+ can_i_sub \
+ echo \
+ eth_serdes \
+ gen_eth_packets \
+ hello \
+ ibs_rx_test \
+ ibs_tx_test \
+ rcv_eth_packets \
+ rx_only_v2 \
+ read_dbids \
+ test1 \
+ test_db_spi \
+ test_i2c \
+ test_phy_comm \
+ test_lsadc \
+ test_lsdac \
+ test_serdes \
+ timer_test \
+ tx_only_v2 \
+ tx_standalone \
+ txrx \
+ serdes_txrx \
+ sd_gentest \
+ sd_bounce
+
+
+# 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
+rx_only_v2_SOURCES = rx_only_v2.c app_common_v2.c
+tx_only_v2_SOURCES = tx_only_v2.c app_common_v2.c
+txrx_SOURCES = txrx.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
+
+noinst_HEADERS = \
+ app_common_v2.h \
+ app_passthru_v2.h
diff --git a/usrp2/firmware/apps/app_common_v2.c b/usrp2/firmware/apps/app_common_v2.c
new file mode 100644
index 000000000..4dc254f85
--- /dev/null
+++ b/usrp2/firmware/apps/app_common_v2.c
@@ -0,0 +1,477 @@
+/* -*- 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_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 "clocks.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;
+
+
+static bool
+burn_mac_addr(const op_burn_mac_addr_t *p)
+{
+ return ethernet_set_mac_addr(&p->addr);
+}
+
+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.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, 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 = 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
+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 (p->valid & CFGV_GAIN){
+ ok &= db_set_gain(tx_dboard, p->gain);
+ }
+
+ if (p->valid & CFGV_FREQ){
+ 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 (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 (p->interp < MIN_INTERP || p->interp > MAX_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;
+ }
+
+ // 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){
+ 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 (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_DECIM || decim > MAX_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 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;
+
+ 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;
+
+ 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
+ */
+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:
+ handle_control_chan_frame(pkt, byte_len);
+ return true; // we handled the packet
+ 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 ? 0x20 : 0x0, 0x20);
+ 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)
+{
+ 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");
+}
diff --git a/usrp2/firmware/apps/app_common_v2.h b/usrp2/firmware/apps/app_common_v2.h
new file mode 100644
index 000000000..30f54876c
--- /dev/null
+++ b/usrp2/firmware/apps/app_common_v2.h
@@ -0,0 +1,62 @@
+/* -*- 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 "bool.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 1 // 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.
+ * 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);
+
+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 u2_mac_addr_t *host, op_start_rx_streaming_t *p);
+void stop_rx_cmd(void);
+
+void handle_control_chan_frame(u2_eth_packet_t *pkt, size_t len);
+
+#endif /* INCLUDED_APP_COMMON_H */
diff --git a/usrp2/firmware/apps/app_passthru_v2.c b/usrp2/firmware/apps/app_passthru_v2.c
new file mode 100644
index 000000000..1689e8b77
--- /dev/null
+++ b/usrp2/firmware/apps/app_passthru_v2.c
@@ -0,0 +1,244 @@
+/* -*- 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.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;
+ }
+
+ 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 ? 0x10 : 0x0, 0x10);
+ printf("\neth link changed: speed = %d\n", speed);
+}
diff --git a/usrp2/firmware/apps/app_passthru_v2.h b/usrp2/firmware/apps/app_passthru_v2.h
new file mode 100644
index 000000000..102243644
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.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 1 // 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/usrp2/firmware/apps/bitrot/tx_drop.c b/usrp2/firmware/apps/bitrot/tx_drop.c
new file mode 100644
index 000000000..d5d6557de
--- /dev/null
+++ b/usrp2/firmware/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 "bool.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.
+u2_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 u2_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/usrp2/firmware/apps/bitrot/tx_drop2.c b/usrp2/firmware/apps/bitrot/tx_drop2.c
new file mode 100644
index 000000000..7f9b7a563
--- /dev/null
+++ b/usrp2/firmware/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 "bool.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.
+u2_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 u2_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/usrp2/firmware/apps/bitrot/tx_drop_rate_limited.c b/usrp2/firmware/apps/bitrot/tx_drop_rate_limited.c
new file mode 100644
index 000000000..0eab25b34
--- /dev/null
+++ b/usrp2/firmware/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 "bool.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.
+u2_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 u2_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/usrp2/firmware/apps/blink_leds.c b/usrp2/firmware/apps/blink_leds.c
new file mode 100644
index 000000000..682ca8db2
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/blink_leds2.c b/usrp2/firmware/apps/blink_leds2.c
new file mode 100644
index 000000000..d4bd89a19
--- /dev/null
+++ b/usrp2/firmware/apps/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_TIMER, timer_handler);
+ hal_set_timeout(DELTA_T); // schedule next timeout
+
+ while(1){
+ hal_toggle_leds(0x1);
+ }
+
+ return 0;
+}
diff --git a/usrp2/firmware/apps/buf_ram_test.c b/usrp2/firmware/apps/buf_ram_test.c
new file mode 100644
index 000000000..e639166a1
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.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/usrp2/firmware/apps/can_i_sub.c b/usrp2/firmware/apps/can_i_sub.c
new file mode 100644
index 000000000..ed49791f0
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/double_buffer_fragment.c b/usrp2/firmware/apps/double_buffer_fragment.c
new file mode 100644
index 000000000..cfc061247
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/echo.c b/usrp2/firmware/apps/echo.c
new file mode 100644
index 000000000..89108ee80
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/eth_serdes.c b/usrp2/firmware/apps/eth_serdes.c
new file mode 100644
index 000000000..c47b8ebd0
--- /dev/null
+++ b/usrp2/firmware/apps/eth_serdes.c
@@ -0,0 +1,230 @@
+/*
+ * 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 "bool.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.
+u2_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();
+
+ 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/usrp2/firmware/apps/gen_eth_packets.c b/usrp2/firmware/apps/gen_eth_packets.c
new file mode 100644
index 000000000..ce1e8160b
--- /dev/null
+++ b/usrp2/firmware/apps/gen_eth_packets.c
@@ -0,0 +1,181 @@
+/*
+ * 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 "bool.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 u2_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;
+ // src address filled in by mac
+
+ 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))){
+ bp_clear_buf(CPU_TX_BUF);
+ npackets_sent++;
+ if ((npackets_sent & 0xF) == 0) // print after every 16 packets
+ print_rmon_regs();
+ }
+
+ 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/usrp2/firmware/apps/gen_pause_frames.c b/usrp2/firmware/apps/gen_pause_frames.c
new file mode 100644
index 000000000..4eaebcc4a
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.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_addr[i] = 0; // filled in by mac
+ }
+ 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/usrp2/firmware/apps/hello.c b/usrp2/firmware/apps/hello.c
new file mode 100644
index 000000000..bce843093
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/ibs_rx_test.c b/usrp2/firmware/apps/ibs_rx_test.c
new file mode 100644
index 000000000..bdc04747e
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/ibs_tx_test.c b/usrp2/firmware/apps/ibs_tx_test.c
new file mode 100644
index 000000000..ff9446d92
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/rcv_eth_packets.c b/usrp2/firmware/apps/rcv_eth_packets.c
new file mode 100644
index 000000000..92e41d92b
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.h"
+#include "ethernet.h"
+#include "nonstdio.h"
+#include "usrp2_eth_packet.h"
+#include "memcpy_wa.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+
+// ----------------------------------------------------------------
+
+static u2_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;
+ // src filled in by mac
+ 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/usrp2/firmware/apps/read_dbids.c b/usrp2/firmware/apps/read_dbids.c
new file mode 100644
index 000000000..4caabd885
--- /dev/null
+++ b/usrp2/firmware/apps/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 <bool.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/usrp2/firmware/apps/rx_only_v2.c b/usrp2/firmware/apps/rx_only_v2.c
new file mode 100644
index 000000000..fc5907415
--- /dev/null
+++ b/usrp2/firmware/apps/rx_only_v2.c
@@ -0,0 +1,263 @@
+/*
+ * 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 "bool.h"
+#include "ethernet.h"
+#include "nonstdio.h"
+#include "usrp2_eth_packet.h"
+#include "memcpy_wa.h"
+#include "dbsm.h"
+#include "app_common_v2.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <db.h>
+#include <db_base.h>
+
+
+#define FW_SETS_SEQNO 1 // define to 0 or 1
+
+#if (FW_SETS_SEQNO)
+static int fw_seqno; // used when f/w is filling in sequence numbers
+#endif
+
+/*
+ * This program can respond to queries from the host
+ * and stream rx samples.
+ *
+ * Buffer 0 is used for rcvd frames from ethernet
+ * 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
+ */
+#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
+
+
+// variables for streaming mode
+
+static bool streaming_p = false;
+static int streaming_frame_count = 0;
+#define FRAMES_PER_CMD 1000
+
+
+/*
+ * ================================================================
+ * configure DSP RX double buffering state machine
+ * ================================================================
+ */
+
+// 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.
+u2_mac_addr_t host_mac_addr;
+
+
+void link_changed_callback(int speed);
+static volatile bool link_is_up = false; // eth handler sets this
+
+
+void
+start_rx_streaming_cmd(const u2_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.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;
+
+ // setup RX DSP regs
+ dsp_rx_regs->clear_state = 1; // reset
+
+ if (1){ // we're streaming
+ streaming_p = true;
+ streaming_frame_count = FRAMES_PER_CMD;
+ dsp_rx_regs->rx_command =
+ MK_RX_CMD(FRAMES_PER_CMD * p->items_per_frame, p->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 * p->items_per_frame, p->items_per_frame,
+ 1, 1);
+ dsp_rx_regs->rx_time = 0; // enqueue second command
+ }
+#if 0
+ else {
+ streaming_p = false;
+ dsp_rx_regs->rx_command =
+ MK_RX_CMD(p->total_samples, p->items_per_frame, p->rx_now, 0);
+
+ // kick off the state machine
+ dbsm_start(&dsp_rx_sm);
+ dsp_rx_regs->rx_time = p->rx_time;
+ }
+#endif
+}
+
+
+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);
+}
+
+inline static void
+buffer_irq_handler(unsigned irq)
+{
+ uint32_t status = buffer_pool_status->status;
+
+ if (status & BPS_DONE(CPU_RX_BUF)){ // we've rcvd a frame from ethernet
+ bp_clear_buf(CPU_RX_BUF);
+ eth_pkt_inspector(0, CPU_RX_BUF);
+ bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE);
+ }
+ if (status & BPS_ERROR(CPU_RX_BUF)){ // error from ethernet
+ bp_clear_buf(CPU_RX_BUF);
+ bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE);
+ }
+
+ dbsm_process_status(&dsp_rx_sm, status);
+
+ if (status & BPS_DONE(CPU_TX_BUF)){
+ bp_clear_buf(CPU_TX_BUF);
+ }
+}
+
+#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
+
+
+int
+main(void)
+{
+ u2_init();
+
+ putstr("\nrx_only_v2\n");
+
+ ethernet_register_link_changed_callback(link_changed_callback);
+ ethernet_init();
+
+ // 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);
+ }
+
+ // setup receive from ETH
+ bp_receive_to_buf(CPU_RX_BUF, PORT_ETH, 1, 0, BP_LAST_LINE);
+
+
+ while(1){
+ buffer_irq_handler(0);
+
+ int pending = pic_regs->pending; // poll for under or overrun
+
+ if (pending & PIC_OVERRUN_INT){
+ dbsm_handle_rx_overrun(&dsp_rx_sm);
+ pic_regs->pending = PIC_OVERRUN_INT; // clear pending interrupt
+ putchar('O');
+ }
+ }
+}
diff --git a/usrp2/firmware/apps/sd_bounce.c b/usrp2/firmware/apps/sd_bounce.c
new file mode 100644
index 000000000..30e3e3fc5
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.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/usrp2/firmware/apps/sd_gentest.c b/usrp2/firmware/apps/sd_gentest.c
new file mode 100644
index 000000000..4824f03f5
--- /dev/null
+++ b/usrp2/firmware/apps/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 "bool.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/usrp2/firmware/apps/serdes_to_dsp.c b/usrp2/firmware/apps/serdes_to_dsp.c
new file mode 100644
index 000000000..ff226bd9f
--- /dev/null
+++ b/usrp2/firmware/apps/serdes_to_dsp.c
@@ -0,0 +1,188 @@
+/*
+ * 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 "bool.h"
+#include "ethernet.h"
+#include "nonstdio.h"
+#include "usrp2_eth_packet.h"
+#include "dbsm.h"
+#include "app_common.h"
+#include <ad9510.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.
+u2_mac_addr_t host_mac_addr;
+
+
+void
+start_rx_cmd(const u2_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
+
+ // if(I WANT TO LOCK TO A REFERENCE CLOCK)
+ // Reg 8, Charge pump on, dig lock det, positive PFD, 47
+ ad9510_write_reg(0x08, 0x47);
+ ad9510_write_reg(0x5A, 0x01); // Update Regs
+ // if (LOCK_TO_MIMO_REF)
+
+ // Turn on ref output and choose the MIMO connector
+ output_regs->clk_ctrl = 0x15;
+ // Turn on ref output and choose the SMA connector
+ //output_regs->clk_ctrl = 0x14;
+
+ // 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/usrp2/firmware/apps/serdes_txrx.c b/usrp2/firmware/apps/serdes_txrx.c
new file mode 100644
index 000000000..8f28a84f1
--- /dev/null
+++ b/usrp2/firmware/apps/serdes_txrx.c
@@ -0,0 +1,346 @@
+/*
+ * 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 "bool.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.
+u2_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
+
+
+// ----------------------------------------------------------------
+
+
+static 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 u2_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.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
+main(void)
+{
+ u2_init();
+
+ 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);
+
+#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, "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);
+
+
+ // 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/usrp2/firmware/apps/test1.c b/usrp2/firmware/apps/test1.c
new file mode 100644
index 000000000..c3cc3be56
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/test_db_spi.c b/usrp2/firmware/apps/test_db_spi.c
new file mode 100644
index 000000000..f4fa98ef1
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/test_i2c.c b/usrp2/firmware/apps/test_i2c.c
new file mode 100644
index 000000000..f349ead88
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/test_lsadc.c b/usrp2/firmware/apps/test_lsadc.c
new file mode 100644
index 000000000..5fda29cd7
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/test_lsdac.c b/usrp2/firmware/apps/test_lsdac.c
new file mode 100644
index 000000000..8c1bf333b
--- /dev/null
+++ b/usrp2/firmware/apps/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/usrp2/firmware/apps/test_phy_comm.c b/usrp2/firmware/apps/test_phy_comm.c
new file mode 100644
index 000000000..7242c6fc8
--- /dev/null
+++ b/usrp2/firmware/apps/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_TIMER, 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/usrp2/firmware/apps/test_serdes.c b/usrp2/firmware/apps/test_serdes.c
new file mode 100644
index 000000000..fadf4d86c
--- /dev/null
+++ b/usrp2/firmware/apps/test_serdes.c
@@ -0,0 +1,192 @@
+/*
+ * 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 "bool.h"
+#include "ethernet.h"
+#include "nonstdio.h"
+#include "usrp2_eth_packet.h"
+#include "memcpy_wa.h"
+#include <stddef.h>
+#include <stdlib.h>
+
+
+// ----------------------------------------------------------------
+
+static u2_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 = 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)));
+
+ pkt.ehdr.dst = dst_mac_addr;
+ // pkt.ehdr.src filled in by mac
+ 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)
+{
+ 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->speed = 4; // FIXME hardcode mac speed to 1000
+ int i = 0;
+ while(1){
+ if (link_is_up && send_packet_now){
+ send_packet_now = false;
+
+ // kick off the next packet
+ // FIXME set packet number in packet
+
+ bp_send_from_buf(i, PORT_SERDES, 1, 0, 255); // 1KB total
+
+ //while ((buffer_pool_status->status & (BPS_DONE_0|BPS_ERROR_0)) == 0)
+ while ((buffer_pool_status->status ) == 0)
+ ;
+ bp_clear_buf(i);
+ i++;
+ if(i==8)
+ i=0;
+ output_regs->leds = ((++led_counter) & 0x1) | (link_is_up ? 0x2 : 0x0);
+ }
+ }
+
+ hal_finish();
+ return 1;
+}
diff --git a/usrp2/firmware/apps/timer_test.c b/usrp2/firmware/apps/timer_test.c
new file mode 100644
index 000000000..7c1e46440
--- /dev/null
+++ b/usrp2/firmware/apps/timer_test.c
@@ -0,0 +1,59 @@
+/*
+ * 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"
+
+
+#define DELTA_T 500 // 5 us (10ns per tick)
+
+
+void
+timer_handler(unsigned irq)
+{
+ int t = timer_regs->time;
+ timer_regs->time = t + DELTA_T;
+
+ putstr("Tick: ");
+ puthex_nl(t);
+}
+
+int
+main(void)
+{
+ u2_init();
+
+ // setup timer
+
+ putstr("Setting up timer\n");
+ pic_register_handler(IRQ_TIMER, timer_handler);
+
+ int t = timer_regs->time;
+ timer_regs->time = t + DELTA_T;
+
+ while (1)
+ ;
+
+ putstr("Done Testing\n");
+
+ hal_finish();
+ return 1;
+}
diff --git a/usrp2/firmware/apps/tx_only_v2.c b/usrp2/firmware/apps/tx_only_v2.c
new file mode 100644
index 000000000..f1e788db6
--- /dev/null
+++ b/usrp2/firmware/apps/tx_only_v2.c
@@ -0,0 +1,171 @@
+/*
+ * 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 "bool.h"
+#include "ethernet.h"
+#include "nonstdio.h"
+#include "usrp2_eth_packet.h"
+#include "dbsm.h"
+#include "app_common_v2.h"
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <db.h>
+#include <db_base.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_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
+
+
+// ----------------------------------------------------------------
+
+
+// The mac address of the host we're sending to.
+u2_mac_addr_t host_mac_addr;
+
+
+void
+start_rx_streaming_cmd(const u2_mac_addr_t *host, op_start_rx_streaming_t *p)
+{
+ // FIXME nop
+}
+
+
+void
+stop_rx_cmd(void)
+{
+ // FIXME nop
+}
+
+
+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;
+}
+
+
+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();
+
+ putstr("\ntx_only_v2\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/usrp2/firmware/apps/tx_standalone.c b/usrp2/firmware/apps/tx_standalone.c
new file mode 100644
index 000000000..25ba8fd40
--- /dev/null
+++ b/usrp2/firmware/apps/tx_standalone.c
@@ -0,0 +1,338 @@
+/*
+ * 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 "bool.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.
+u2_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.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
+ u2_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/usrp2/firmware/apps/txrx.c b/usrp2/firmware/apps/txrx.c
new file mode 100644
index 000000000..13aa8ba2b
--- /dev/null
+++ b/usrp2/firmware/apps/txrx.c
@@ -0,0 +1,344 @@
+/*
+ * 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 "bool.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>
+
+
+#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.
+u2_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
+
+
+// ----------------------------------------------------------------
+
+
+static 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 u2_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.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
+main(void)
+{
+ u2_init();
+
+ putstr("\nTxRx\n");
+ print_mac_addr(ethernet_mac_addr()->addr);
+ newline();
+
+ ethernet_register_link_changed_callback(link_changed_callback);
+ ethernet_init();
+
+
+#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');
+ }
+ }
+}