aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/control_lib
diff options
context:
space:
mode:
authorMartin Braun <martin.braun@ettus.com>2020-01-23 16:10:22 -0800
committerMartin Braun <martin.braun@ettus.com>2020-01-28 09:35:36 -0800
commitbafa9d95453387814ef25e6b6256ba8db2df612f (patch)
tree39ba24b5b67072d354775272e687796bb511848d /fpga/usrp2/control_lib
parent3075b981503002df3115d5f1d0b97d2619ba30f2 (diff)
downloaduhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz
uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2
uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce the size of the repository. However, over the last half-decade, the split between the repositories has proven more burdensome than it has been helpful. By merging the FPGA code back, it will be possible to create atomic commits that touch both FPGA and UHD codebases. Continuous integration testing is also simplified by merging the repositories, because it was previously difficult to automatically derive the correct UHD branch when testing a feature branch on the FPGA repository. This commit also updates the license files and paths therein. We are therefore merging the repositories again. Future development for FPGA code will happen in the same repository as the UHD host code and MPM code. == Original Codebase and Rebasing == The original FPGA repository will be hosted for the foreseeable future at its original local location: https://github.com/EttusResearch/fpga/ It can be used for bisecting, reference, and a more detailed history. The final commit from said repository to be merged here is 05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as v4.0.0.0-pre-uhd-merge. If you have changes in the FPGA repository that you want to rebase onto the UHD repository, simply run the following commands: - Create a directory to store patches (this should be an empty directory): mkdir ~/patches - Now make sure that your FPGA codebase is based on the same state as the code that was merged: cd src/fpga # Or wherever your FPGA code is stored git rebase v4.0.0.0-pre-uhd-merge Note: The rebase command may look slightly different depending on what exactly you're trying to rebase. - Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge: git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches Note: Make sure that only patches are stored in your output directory. It should otherwise be empty. Make sure that you picked the correct range of commits, and only commits you wanted to rebase were exported as patch files. - Go to the UHD repository and apply the patches: cd src/uhd # Or wherever your UHD repository is stored git am --directory fpga ~/patches/* rm -rf ~/patches # This is for cleanup == Contributors == The following people have contributed mainly to these files (this list is not complete): Co-authored-by: Alex Williams <alex.williams@ni.com> Co-authored-by: Andrej Rode <andrej.rode@ettus.com> Co-authored-by: Ashish Chaudhari <ashish@ettus.com> Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com> Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com> Co-authored-by: Daniel Jepson <daniel.jepson@ni.com> Co-authored-by: Derek Kozel <derek.kozel@ettus.com> Co-authored-by: EJ Kreinar <ej@he360.com> Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com> Co-authored-by: Ian Buckley <ian.buckley@gmail.com> Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com> Co-authored-by: Jon Kiser <jon.kiser@ni.com> Co-authored-by: Josh Blum <josh@joshknows.com> Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com> Co-authored-by: Martin Braun <martin.braun@ettus.com> Co-authored-by: Matt Ettus <matt@ettus.com> Co-authored-by: Michael West <michael.west@ettus.com> Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com> Co-authored-by: Nick Foster <nick@ettus.com> Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com> Co-authored-by: Paul Butler <paul.butler@ni.com> Co-authored-by: Paul David <paul.david@ettus.com> Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com> Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com> Co-authored-by: Sylvain Munaut <tnt@246tNt.com> Co-authored-by: Trung Tran <trung.tran@ettus.com> Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com> Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp2/control_lib')
-rw-r--r--fpga/usrp2/control_lib/.gitignore5
-rw-r--r--fpga/usrp2/control_lib/CRC16_D16.v89
-rw-r--r--fpga/usrp2/control_lib/Makefile.srcs61
-rw-r--r--fpga/usrp2/control_lib/atr_controller.v77
-rw-r--r--fpga/usrp2/control_lib/atr_controller16.v79
-rw-r--r--fpga/usrp2/control_lib/bin2gray.v27
-rw-r--r--fpga/usrp2/control_lib/bootram.v312
-rw-r--r--fpga/usrp2/control_lib/bootrom.mem26
-rw-r--r--fpga/usrp2/control_lib/clock_bootstrap_rom.v51
-rw-r--r--fpga/usrp2/control_lib/clock_control.v132
-rw-r--r--fpga/usrp2/control_lib/clock_control_tb.v52
-rw-r--r--fpga/usrp2/control_lib/cmdfile18
-rw-r--r--fpga/usrp2/control_lib/dbsm.v164
-rw-r--r--fpga/usrp2/control_lib/dcache.v182
-rw-r--r--fpga/usrp2/control_lib/decoder_3_8.v38
-rw-r--r--fpga/usrp2/control_lib/double_buffer.v139
-rw-r--r--fpga/usrp2/control_lib/double_buffer_tb.v312
-rw-r--r--fpga/usrp2/control_lib/dpram32.v99
-rw-r--r--fpga/usrp2/control_lib/fifo_to_wb.v183
-rw-r--r--fpga/usrp2/control_lib/fifo_to_wb_tb.v136
-rw-r--r--fpga/usrp2/control_lib/gpio_atr.v71
-rw-r--r--fpga/usrp2/control_lib/gray2bin.v30
-rw-r--r--fpga/usrp2/control_lib/gray_send.v46
-rw-r--r--fpga/usrp2/control_lib/icache.v152
-rw-r--r--fpga/usrp2/control_lib/longfifo.v167
-rw-r--r--fpga/usrp2/control_lib/medfifo.v66
-rw-r--r--fpga/usrp2/control_lib/mux4.v33
-rw-r--r--fpga/usrp2/control_lib/mux8.v38
-rw-r--r--fpga/usrp2/control_lib/mux_32_4.v30
-rw-r--r--fpga/usrp2/control_lib/nsgpio.v93
-rw-r--r--fpga/usrp2/control_lib/nsgpio16LE.v123
-rw-r--r--fpga/usrp2/control_lib/oneshot_2clk.v52
-rw-r--r--fpga/usrp2/control_lib/pic.v183
-rw-r--r--fpga/usrp2/control_lib/priority_enc.v61
-rw-r--r--fpga/usrp2/control_lib/quad_uart.v88
-rw-r--r--fpga/usrp2/control_lib/ram_2port.v59
-rw-r--r--fpga/usrp2/control_lib/ram_2port_mixed_width.v137
-rw-r--r--fpga/usrp2/control_lib/ram_harv_cache.v92
-rw-r--r--fpga/usrp2/control_lib/ram_harvard.v84
-rw-r--r--fpga/usrp2/control_lib/ram_harvard2.v94
-rw-r--r--fpga/usrp2/control_lib/ram_loader.v278
-rw-r--r--fpga/usrp2/control_lib/ram_wb_harvard.v103
-rw-r--r--fpga/usrp2/control_lib/reset_sync.v33
-rw-r--r--fpga/usrp2/control_lib/s3a_icap_wb.v76
-rw-r--r--fpga/usrp2/control_lib/sd_spi.v87
-rw-r--r--fpga/usrp2/control_lib/sd_spi_tb.v57
-rw-r--r--fpga/usrp2/control_lib/sd_spi_wb.v93
-rw-r--r--fpga/usrp2/control_lib/setting_reg.v42
-rw-r--r--fpga/usrp2/control_lib/settings_bus.v58
-rw-r--r--fpga/usrp2/control_lib/settings_bus_16LE.v71
-rw-r--r--fpga/usrp2/control_lib/settings_bus_crossclock.v38
-rw-r--r--fpga/usrp2/control_lib/settings_fifo_ctrl.v428
-rw-r--r--fpga/usrp2/control_lib/shortfifo.v104
-rw-r--r--fpga/usrp2/control_lib/simple_i2c_core.v116
-rw-r--r--fpga/usrp2/control_lib/simple_spi_core.v214
-rw-r--r--fpga/usrp2/control_lib/simple_uart.v79
-rw-r--r--fpga/usrp2/control_lib/simple_uart_rx.v81
-rw-r--r--fpga/usrp2/control_lib/simple_uart_tx.v77
-rw-r--r--fpga/usrp2/control_lib/spi.v101
-rw-r--r--fpga/usrp2/control_lib/srl.v38
-rw-r--r--fpga/usrp2/control_lib/ss_rcvr.v98
-rw-r--r--fpga/usrp2/control_lib/system_control.v64
-rw-r--r--fpga/usrp2/control_lib/system_control_tb.v74
-rw-r--r--fpga/usrp2/control_lib/traffic_cop.v42
-rw-r--r--fpga/usrp2/control_lib/user_settings.v63
-rw-r--r--fpga/usrp2/control_lib/v5icap_wb.v71
-rw-r--r--fpga/usrp2/control_lib/wb_1master.v464
-rw-r--r--fpga/usrp2/control_lib/wb_bridge_16_32.v53
-rw-r--r--fpga/usrp2/control_lib/wb_bus_writer.v74
-rw-r--r--fpga/usrp2/control_lib/wb_output_pins32.v66
-rw-r--r--fpga/usrp2/control_lib/wb_ram_block.v53
-rw-r--r--fpga/usrp2/control_lib/wb_ram_dist.v50
-rw-r--r--fpga/usrp2/control_lib/wb_readback_mux.v77
-rw-r--r--fpga/usrp2/control_lib/wb_readback_mux_16LE.v90
-rw-r--r--fpga/usrp2/control_lib/wb_regfile_2clock.v124
-rw-r--r--fpga/usrp2/control_lib/wb_semaphore.v59
-rw-r--r--fpga/usrp2/control_lib/wb_sim.v96
77 files changed, 7673 insertions, 0 deletions
diff --git a/fpga/usrp2/control_lib/.gitignore b/fpga/usrp2/control_lib/.gitignore
new file mode 100644
index 000000000..025385cff
--- /dev/null
+++ b/fpga/usrp2/control_lib/.gitignore
@@ -0,0 +1,5 @@
+/a.out
+/*.vcd
+/*.lxt
+/*.sav
+/*.log
diff --git a/fpga/usrp2/control_lib/CRC16_D16.v b/fpga/usrp2/control_lib/CRC16_D16.v
new file mode 100644
index 000000000..7e2816af1
--- /dev/null
+++ b/fpga/usrp2/control_lib/CRC16_D16.v
@@ -0,0 +1,89 @@
+///////////////////////////////////////////////////////////////////////
+// File: CRC16_D16.v
+// Date: Sun Jun 17 06:42:55 2007
+//
+// Copyright (C) 1999-2003 Easics NV.
+// This source file may be used and distributed without restriction
+// provided that this copyright statement is not removed from the file
+// and that any derivative work contains the original copyright notice
+// and the associated disclaimer.
+//
+// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Purpose: Verilog module containing a synthesizable CRC function
+// * polynomial: (0 5 12 16)
+// * data width: 16
+//
+// Info: tools@easics.be
+// http://www.easics.com
+///////////////////////////////////////////////////////////////////////
+
+
+module CRC16_D16
+ (input [15:0] Data,
+ input [15:0] CRC,
+ output [15:0] NewCRC);
+
+ assign NewCRC = nextCRC16_D16(Data,CRC);
+
+ // polynomial: (0 5 12 16)
+ // data width: 16
+ // convention: the first serial data bit is D[15]
+ function [15:0] nextCRC16_D16;
+
+ input [15:0] Data;
+ input [15:0] CRC;
+
+ reg [15:0] D;
+ reg [15:0] C;
+ reg [15:0] NewCRC;
+
+ begin
+
+ D = Data;
+ C = CRC;
+
+ NewCRC[0] = D[12] ^ D[11] ^ D[8] ^ D[4] ^ D[0] ^ C[0] ^ C[4] ^
+ C[8] ^ C[11] ^ C[12];
+ NewCRC[1] = D[13] ^ D[12] ^ D[9] ^ D[5] ^ D[1] ^ C[1] ^ C[5] ^
+ C[9] ^ C[12] ^ C[13];
+ NewCRC[2] = D[14] ^ D[13] ^ D[10] ^ D[6] ^ D[2] ^ C[2] ^ C[6] ^
+ C[10] ^ C[13] ^ C[14];
+ NewCRC[3] = D[15] ^ D[14] ^ D[11] ^ D[7] ^ D[3] ^ C[3] ^ C[7] ^
+ C[11] ^ C[14] ^ C[15];
+ NewCRC[4] = D[15] ^ D[12] ^ D[8] ^ D[4] ^ C[4] ^ C[8] ^ C[12] ^
+ C[15];
+ NewCRC[5] = D[13] ^ D[12] ^ D[11] ^ D[9] ^ D[8] ^ D[5] ^ D[4] ^
+ D[0] ^ C[0] ^ C[4] ^ C[5] ^ C[8] ^ C[9] ^ C[11] ^ C[12] ^
+ C[13];
+ NewCRC[6] = D[14] ^ D[13] ^ D[12] ^ D[10] ^ D[9] ^ D[6] ^ D[5] ^
+ D[1] ^ C[1] ^ C[5] ^ C[6] ^ C[9] ^ C[10] ^ C[12] ^
+ C[13] ^ C[14];
+ NewCRC[7] = D[15] ^ D[14] ^ D[13] ^ D[11] ^ D[10] ^ D[7] ^ D[6] ^
+ D[2] ^ C[2] ^ C[6] ^ C[7] ^ C[10] ^ C[11] ^ C[13] ^
+ C[14] ^ C[15];
+ NewCRC[8] = D[15] ^ D[14] ^ D[12] ^ D[11] ^ D[8] ^ D[7] ^ D[3] ^
+ C[3] ^ C[7] ^ C[8] ^ C[11] ^ C[12] ^ C[14] ^ C[15];
+ NewCRC[9] = D[15] ^ D[13] ^ D[12] ^ D[9] ^ D[8] ^ D[4] ^ C[4] ^
+ C[8] ^ C[9] ^ C[12] ^ C[13] ^ C[15];
+ NewCRC[10] = D[14] ^ D[13] ^ D[10] ^ D[9] ^ D[5] ^ C[5] ^ C[9] ^
+ C[10] ^ C[13] ^ C[14];
+ NewCRC[11] = D[15] ^ D[14] ^ D[11] ^ D[10] ^ D[6] ^ C[6] ^ C[10] ^
+ C[11] ^ C[14] ^ C[15];
+ NewCRC[12] = D[15] ^ D[8] ^ D[7] ^ D[4] ^ D[0] ^ C[0] ^ C[4] ^ C[7] ^
+ C[8] ^ C[15];
+ NewCRC[13] = D[9] ^ D[8] ^ D[5] ^ D[1] ^ C[1] ^ C[5] ^ C[8] ^ C[9];
+ NewCRC[14] = D[10] ^ D[9] ^ D[6] ^ D[2] ^ C[2] ^ C[6] ^ C[9] ^ C[10];
+ NewCRC[15] = D[11] ^ D[10] ^ D[7] ^ D[3] ^ C[3] ^ C[7] ^ C[10] ^
+ C[11];
+
+ nextCRC16_D16 = NewCRC;
+
+ end
+
+ endfunction
+
+endmodule
+
diff --git a/fpga/usrp2/control_lib/Makefile.srcs b/fpga/usrp2/control_lib/Makefile.srcs
new file mode 100644
index 000000000..42862a50f
--- /dev/null
+++ b/fpga/usrp2/control_lib/Makefile.srcs
@@ -0,0 +1,61 @@
+#
+# Copyright 2010-2012 Ettus Research LLC
+#
+
+##################################################
+# Control Lib Sources
+##################################################
+CONTROL_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../control_lib/, \
+CRC16_D16.v \
+atr_controller.v \
+bin2gray.v \
+dcache.v \
+decoder_3_8.v \
+dbsm.v \
+dpram32.v \
+double_buffer.v \
+gray2bin.v \
+gray_send.v \
+icache.v \
+mux4.v \
+mux8.v \
+nsgpio.v \
+ram_2port.v \
+ram_harv_cache.v \
+ram_harvard.v \
+ram_harvard2.v \
+ram_loader.v \
+setting_reg.v \
+settings_bus.v \
+settings_bus_crossclock.v \
+srl.v \
+system_control.v \
+wb_1master.v \
+wb_readback_mux.v \
+wb_readback_mux_16LE.v \
+quad_uart.v \
+simple_uart.v \
+simple_uart_tx.v \
+simple_uart_rx.v \
+oneshot_2clk.v \
+sd_spi.v \
+sd_spi_wb.v \
+wb_bridge_16_32.v \
+reset_sync.v \
+priority_enc.v \
+pic.v \
+longfifo.v \
+shortfifo.v \
+medfifo.v \
+s3a_icap_wb.v \
+bootram.v \
+nsgpio16LE.v \
+settings_bus_16LE.v \
+atr_controller16.v \
+fifo_to_wb.v \
+gpio_atr.v \
+user_settings.v \
+settings_fifo_ctrl.v \
+simple_spi_core.v \
+simple_i2c_core.v \
+))
diff --git a/fpga/usrp2/control_lib/atr_controller.v b/fpga/usrp2/control_lib/atr_controller.v
new file mode 100644
index 000000000..ee8b260c5
--- /dev/null
+++ b/fpga/usrp2/control_lib/atr_controller.v
@@ -0,0 +1,77 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Automatic transmit/receive switching of control pins to daughterboards
+// Store everything in registers for now, but could use a RAM for more
+// complex state machines in the future
+
+module atr_controller
+ (input clk_i, input rst_i,
+ input [5:0] adr_i, input [3:0] sel_i, input [31:0] dat_i, output reg [31:0] dat_o,
+ input we_i, input stb_i, input cyc_i, output reg ack_o,
+ input run_rx, input run_tx,
+ output [31:0] ctrl_lines);
+
+ reg [3:0] state;
+ reg [31:0] atr_ram [0:15]; // DP distributed RAM
+
+ // WB Interface
+ always @(posedge clk_i)
+ if(we_i & stb_i & cyc_i)
+ begin
+ if(sel_i[3])
+ atr_ram[adr_i[5:2]][31:24] <= dat_i[31:24];
+ if(sel_i[2])
+ atr_ram[adr_i[5:2]][23:16] <= dat_i[23:16];
+ if(sel_i[1])
+ atr_ram[adr_i[5:2]][15:8] <= dat_i[15:8];
+ if(sel_i[0])
+ atr_ram[adr_i[5:2]][7:0] <= dat_i[7:0];
+ end // if (we_i & stb_i & cyc_i)
+
+ // Removing readback allows ram to be synthesized as LUTs instead of regs
+ //always @(posedge clk_i)
+ // dat_o <= atr_ram[adr_i[5:2]];
+ always
+ dat_o <= 32'd0;
+
+ always @(posedge clk_i)
+ ack_o <= stb_i & cyc_i & ~ack_o;
+
+ // Control side of DP RAM
+ assign ctrl_lines = atr_ram[state];
+
+ // Put a more complex state machine with time delays and multiple states here
+ // if daughterboard requires more complex sequencing
+ localparam ATR_IDLE = 4'd0;
+ localparam ATR_TX = 4'd1;
+ localparam ATR_RX = 4'd2;
+ localparam ATR_FULL_DUPLEX = 4'd3;
+
+ always @(posedge clk_i)
+ if(rst_i)
+ state <= ATR_IDLE;
+ else
+ case ({run_rx,run_tx})
+ 2'b00 : state <= ATR_IDLE;
+ 2'b01 : state <= ATR_TX;
+ 2'b10 : state <= ATR_RX;
+ 2'b11 : state <= ATR_FULL_DUPLEX;
+ endcase // case({run_rx,run_tx})
+
+endmodule // atr_controller
diff --git a/fpga/usrp2/control_lib/atr_controller16.v b/fpga/usrp2/control_lib/atr_controller16.v
new file mode 100644
index 000000000..578da4a5c
--- /dev/null
+++ b/fpga/usrp2/control_lib/atr_controller16.v
@@ -0,0 +1,79 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Automatic transmit/receive switching of control pins to daughterboards
+// Store everything in registers for now, but could use a RAM for more
+// complex state machines in the future
+
+module atr_controller16
+ (input clk_i, input rst_i,
+ input [5:0] adr_i, input [1:0] sel_i, input [15:0] dat_i, output [15:0] dat_o,
+ input we_i, input stb_i, input cyc_i, output reg ack_o,
+ input run_rx, input run_tx,
+ output [31:0] ctrl_lines);
+
+ reg [3:0] state;
+ reg [31:0] atr_ram [0:15]; // DP distributed RAM
+
+ wire [3:0] sel_int = { (sel_i[1] & adr_i[1]), (sel_i[0] & adr_i[1]),
+ (sel_i[1] & ~adr_i[1]), (sel_i[0] & ~adr_i[1]) };
+
+ // WB Interface
+ always @(posedge clk_i)
+ if(we_i & stb_i & cyc_i)
+ begin
+ if(sel_int[3])
+ atr_ram[adr_i[5:2]][31:24] <= dat_i[15:8];
+ if(sel_int[2])
+ atr_ram[adr_i[5:2]][23:16] <= dat_i[7:0];
+ if(sel_int[1])
+ atr_ram[adr_i[5:2]][15:8] <= dat_i[15:8];
+ if(sel_int[0])
+ atr_ram[adr_i[5:2]][7:0] <= dat_i[7:0];
+ end // if (we_i & stb_i & cyc_i)
+
+ // Removing readback allows ram to be synthesized as LUTs instead of regs
+ //always @(posedge clk_i)
+ // dat_o <= adr_i[1] ? atr_ram[adr_i[5:2]][31:16] : atr_ram[adr_i[5:2]][15:0];
+ assign dat_o = 16'd0;
+
+ always @(posedge clk_i)
+ ack_o <= stb_i & cyc_i & ~ack_o;
+
+ // Control side of DP RAM
+ assign ctrl_lines = atr_ram[state];
+
+ // Put a more complex state machine with time delays and multiple states here
+ // if daughterboard requires more complex sequencing
+ localparam ATR_IDLE = 4'd0;
+ localparam ATR_TX = 4'd1;
+ localparam ATR_RX = 4'd2;
+ localparam ATR_FULL_DUPLEX = 4'd3;
+
+ always @(posedge clk_i)
+ if(rst_i)
+ state <= ATR_IDLE;
+ else
+ case ({run_rx,run_tx})
+ 2'b00 : state <= ATR_IDLE;
+ 2'b01 : state <= ATR_TX;
+ 2'b10 : state <= ATR_RX;
+ 2'b11 : state <= ATR_FULL_DUPLEX;
+ endcase // case({run_rx,run_tx})
+
+endmodule // atr_controller16
diff --git a/fpga/usrp2/control_lib/bin2gray.v b/fpga/usrp2/control_lib/bin2gray.v
new file mode 100644
index 000000000..8336a5afc
--- /dev/null
+++ b/fpga/usrp2/control_lib/bin2gray.v
@@ -0,0 +1,27 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module bin2gray
+ #(parameter WIDTH=8)
+ (input [WIDTH-1:0] bin,
+ output [WIDTH-1:0] gray);
+
+ assign gray = (bin >> 1) ^ bin;
+
+endmodule // bin2gray
diff --git a/fpga/usrp2/control_lib/bootram.v b/fpga/usrp2/control_lib/bootram.v
new file mode 100644
index 000000000..7821fbc4c
--- /dev/null
+++ b/fpga/usrp2/control_lib/bootram.v
@@ -0,0 +1,312 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Boot RAM for S3A, 8KB, dual port
+
+// RAMB16BWE_S36_S36: 512 x 32 + 4 Parity bits byte-wide write Dual-Port RAM
+// Spartan-3A Xilinx HDL Libraries Guide, version 10.1.1
+
+module bootram
+ (input clk, input reset,
+ input [13:0] if_adr,
+ output [31:0] if_data,
+
+ input [13:0] dwb_adr_i,
+ input [31:0] dwb_dat_i,
+ output [31:0] dwb_dat_o,
+ input dwb_we_i,
+ output reg dwb_ack_o,
+ input dwb_stb_i,
+ input [3:0] dwb_sel_i);
+
+ wire [31:0] DOA0, DOA1, DOA2, DOA3, DOA4, DOA5, DOA6, DOA7;
+ wire [31:0] DOB0, DOB1, DOB2, DOB3, DOB4, DOB5, DOB6, DOB7;
+ wire ENB0, ENB1, ENB2, ENB3, ENB4, ENB5, ENB6, ENB7;
+ wire [3:0] WEB;
+
+ reg [2:0] delayed_if_bank;
+ always @(posedge clk)
+ delayed_if_bank <= if_adr[13:11];
+
+ assign if_data = delayed_if_bank[2] ?
+ (delayed_if_bank[1] ? (delayed_if_bank[0] ? DOA7 : DOA6) : (delayed_if_bank[0] ? DOA5 : DOA4))
+ : (delayed_if_bank[1] ? (delayed_if_bank[0] ? DOA3 : DOA2) : (delayed_if_bank[0] ? DOA1 : DOA0));
+
+
+ assign dwb_dat_o = dwb_adr_i[13] ?
+ (dwb_adr_i[12] ? (dwb_adr_i[11] ? DOB7 : DOB6) : (dwb_adr_i[11] ? DOB5 : DOB4))
+ : (dwb_adr_i[12] ? (dwb_adr_i[11] ? DOB3 : DOB2) : (dwb_adr_i[11] ? DOB1 : DOB0));
+
+ always @(posedge clk)
+ if(reset)
+ dwb_ack_o <= 0;
+ else
+ dwb_ack_o <= dwb_stb_i & ~dwb_ack_o;
+
+ assign ENB0 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b000);
+ assign ENB1 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b001);
+ assign ENB2 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b010);
+ assign ENB3 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b011);
+ assign ENB4 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b100);
+ assign ENB5 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b101);
+ assign ENB6 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b110);
+ assign ENB7 = dwb_stb_i & (dwb_adr_i[13:11] == 3'b111);
+
+ assign WEB = {4{dwb_we_i}} & dwb_sel_i;
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM0
+ (.DOA(DOA0), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB0), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB0), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM1
+ (.DOA(DOA1), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB1), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB1), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM2
+ (.DOA(DOA2), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB2), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB2), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM3
+ (.DOA(DOA3), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB3), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB3), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM4
+ (.DOA(DOA4), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB4), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB4), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM5
+ (.DOA(DOA5), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB5), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB5), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM6
+ (.DOA(DOA6), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB6), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB6), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+ RAMB16BWE_S36_S36
+ #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup
+ .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ RAM7
+ (.DOA(DOA7), // Port A 32-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input
+ .CLKA(clk), // Port A 1-bit Clock
+ .DIA(32'hffffffff), // Port A 32-bit Data Input
+ .DIPA(4'hf), // Port A 4-bit parity Input
+ .ENA(1'b1), // Port A 1-bit RAM Enable Input
+ .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input
+ .WEA(1'b0), // Port A 4-bit Write Enable Input
+
+ .DOB(DOB7), // Port B 32-bit Data Output
+ .DOPB(), // Port B 4-bit Parity Output
+ .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input
+ .CLKB(clk), // Port B 1-bit Clock
+ .DIB(dwb_dat_i), // Port B 32-bit Data Input
+ .DIPB(4'hf), // Port-B 4-bit parity Input
+ .ENB(ENB7), // Port B 1-bit RAM Enable Input
+ .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEB(WEB) // Port B 4-bit Write Enable Input
+ ); // End of RAMB16BWE_S36_S36_inst instantiation
+
+endmodule // bootram
diff --git a/fpga/usrp2/control_lib/bootrom.mem b/fpga/usrp2/control_lib/bootrom.mem
new file mode 100644
index 000000000..d688b4342
--- /dev/null
+++ b/fpga/usrp2/control_lib/bootrom.mem
@@ -0,0 +1,26 @@
+00000C000F03
+101400000000
+ // SPI: Set Divider to div by 2
+// Both clk sel choose ext ref (0), both are enabled (1), turn off SERDES, ADCs, turn on leds
+1018_0000_0001 // SPI: Choose AD9510
+1010_0000_3418 // SPI: Auto-slave select, interrupt when done, TX_NEG, 24-bit word
+1000_0000_0010 // SPI: AD9510 A:0 D:10 Set up AD9510 SPI
+1010_0000_3518 // SPI: SEND IT Auto-slave select, interrupt when done, TX_NEG, 24-bit word
+ffff_ffff_ffff // terminate
+#// First 16 bits are address, last 32 are data
+#// First 4 bits of address select which slave
+// 6'd01 : addr_data = {13'h45,8'h00}; // CLK2 drives distribution, everything on
+// 6'd02 : addr_data = {13'h3D,8'h80}; // Turn on output 1, normal levels
+// 6'd03 : addr_data = {13'h4B,8'h80}; // Bypass divider 1 (div by 1)
+// 6'd04 : addr_data = {13'h08,8'h47}; // POS PFD, Dig LK Det, Charge Pump normal
+// 6'd05 : addr_data = {13'h09,8'h70}; // Max Charge Pump current
+// 6'd06 : addr_data = {13'h0A,8'h04}; // Normal operation, Prescalar Div by 2, PLL On
+// 6'd07 : addr_data = {13'h0B,8'h00}; // RDIV MSB (6 bits)
+// 6'd08 : addr_data = {13'h0C,8'h01}; // RDIV LSB (8 bits), Div by 1
+// 6'd09 : addr_data = {13'h0D,8'h00}; // Everything normal, Dig Lock Det
+// 6'd10 : addr_data = {13'h07,8'h00}; // Disable LOR detect - LOR causes failure...
+// 6'd11 : addr_data = {13'h04,8'h00}; // A Counter = Don't Care
+// 6'd12 : addr_data = {13'h05,8'h00}; // B Counter MSB = 0
+// 6'd13 : addr_data = {13'h06,8'h05}; // B Counter LSB = 5
+ // default : addr_data = {13'h5A,8'h01}; // Register Update
+// @ 55 // Jump to new address 8'h55
diff --git a/fpga/usrp2/control_lib/clock_bootstrap_rom.v b/fpga/usrp2/control_lib/clock_bootstrap_rom.v
new file mode 100644
index 000000000..542f49380
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_bootstrap_rom.v
@@ -0,0 +1,51 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module clock_bootstrap_rom(input [15:0] addr, output [47:0] data);
+
+ reg [47:0] rom [0:15];
+
+ //initial
+ // $readmemh("bootrom.mem", rom);
+
+ assign data = rom[addr];
+
+ initial
+ begin
+ // First 16 bits are address, last 32 are data
+ // First 4 bits of address select which slave
+ rom[0] = 48'h0000_0C00_0F03; // Both clk sel choose ext ref (0), both are enabled (1), turn off SERDES, ADCs, turn on leds
+ rom[1] = 48'h1014_0000_0000; // SPI: Set Divider to div by 2
+ rom[2] = 48'h1018_0000_0001; // SPI: Choose AD9510
+ rom[3] = 48'h1010_0000_3418; // SPI: Auto-slave select, interrupt when done, TX_NEG, 24-bit word
+ rom[4] = 48'h1000_0000_0010; // SPI: AD9510 A:0 D:10 Set up AD9510 SPI
+ rom[5] = 48'h1010_0000_3518; // SPI: SEND IT Auto-slave select, interrupt when done, TX_NEG, 24-bit word
+ rom[6] = 48'hffff_ffff_ffff; // terminate
+ rom[7] = 48'hffff_ffff_ffff; // terminate
+ rom[8] = 48'hffff_ffff_ffff; // terminate
+ rom[9] = 48'hffff_ffff_ffff; // terminate
+ rom[10] = 48'hffff_ffff_ffff; // terminate
+ rom[11] = 48'hffff_ffff_ffff; // terminate
+ rom[12] = 48'hffff_ffff_ffff; // terminate
+ rom[13] = 48'hffff_ffff_ffff; // terminate
+ rom[14] = 48'hffff_ffff_ffff; // terminate
+ rom[15] = 48'hffff_ffff_ffff; // terminate
+ end // initial begin
+
+endmodule // clock_bootstrap_rom
diff --git a/fpga/usrp2/control_lib/clock_control.v b/fpga/usrp2/control_lib/clock_control.v
new file mode 100644
index 000000000..000eaf1fb
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_control.v
@@ -0,0 +1,132 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// AD9510 Register Map (from datasheet Rev. A)
+
+/* INSTRUCTION word format (16 bits)
+ * 15 Read = 1, Write = 0
+ * 14:13 W1/W0, Number of bytes 00 - 1, 01 - 2, 10 - 3, 11 - stream
+ * 12:0 Address
+ */
+
+/* ADDR Contents Value (hex)
+ * 00 Serial Config Port 10 (def) -- MSB first, SDI/SDO separate
+ * 04 A Counter
+ * 05-06 B Counter
+ * 07-0A PLL Control
+ * 0B-0C R Divider
+ * 0D PLL Control
+ * 34-3A Fine Delay
+ * 3C-3F LVPECL Outs
+ * 40-43 LVDS/CMOS Outs
+ * 45 Clock select, power down
+ * 48-57 Dividers
+ * 58 Func and Sync
+ * 5A Update regs
+ */
+
+
+module clock_control
+ (input reset,
+ input aux_clk, // 25MHz, for before fpga clock is active
+ input clk_fpga, // real 100 MHz FPGA clock
+ output [1:0] clk_en, // controls source of reference clock
+ output [1:0] clk_sel, // controls source of reference clock
+ input clk_func, // FIXME needs to be some kind of out SYNC or reset to 9510
+ input clk_status, // Monitor PLL or SYNC status
+
+ output sen, // Enable for the AD9510
+ output sclk, // FIXME these need to be shared
+ input sdi,
+ output sdo
+ );
+
+ wire read = 1'b0; // Always write for now
+ wire [1:0] w = 2'b00; // Always send 1 byte at a time
+
+ assign clk_sel = 2'b00; // Both outputs from External Ref (SMA)
+ assign clk_en = 2'b11; // Both outputs enabled
+
+ reg [20:0] addr_data;
+
+ reg [5:0] entry;
+ reg start;
+ reg [7:0] counter;
+ reg [23:0] command;
+
+ always @*
+ case(entry)
+ 6'd00 : addr_data = {13'h00,8'h10}; // Serial setup
+ 6'd01 : addr_data = {13'h45,8'h00}; // CLK2 drives distribution, everything on
+ 6'd02 : addr_data = {13'h3D,8'h80}; // Turn on output 1, normal levels
+ 6'd03 : addr_data = {13'h4B,8'h80}; // Bypass divider 1 (div by 1)
+ 6'd04 : addr_data = {13'h08,8'h47}; // POS PFD, Dig LK Det, Charge Pump normal
+ 6'd05 : addr_data = {13'h09,8'h70}; // Max Charge Pump current
+ 6'd06 : addr_data = {13'h0A,8'h04}; // Normal operation, Prescalar Div by 2, PLL On
+ 6'd07 : addr_data = {13'h0B,8'h00}; // RDIV MSB (6 bits)
+ 6'd08 : addr_data = {13'h0C,8'h01}; // RDIV LSB (8 bits), Div by 1
+ 6'd09 : addr_data = {13'h0D,8'h00}; // Everything normal, Dig Lock Det
+ 6'd10 : addr_data = {13'h07,8'h00}; // Disable LOR detect - LOR causes failure...
+ 6'd11 : addr_data = {13'h04,8'h00}; // A Counter = Don't Care
+ 6'd12 : addr_data = {13'h05,8'h00}; // B Counter MSB = 0
+ 6'd13 : addr_data = {13'h06,8'h05}; // B Counter LSB = 5
+ default : addr_data = {13'h5A,8'h01}; // Register Update
+ endcase // case(entry)
+
+ wire [5:0] lastentry = 6'd15;
+ wire done = (counter == 8'd49);
+
+ always @(posedge aux_clk)
+ if(reset)
+ begin
+ entry <= #1 6'd0;
+ start <= #1 1'b1;
+ end
+ else if(start)
+ start <= #1 1'b0;
+ else if(done && (entry<lastentry))
+ begin
+ entry <= #1 entry + 6'd1;
+ start <= #1 1'b1;
+ end
+
+ always @(posedge aux_clk)
+ if(reset)
+ begin
+ counter <= #1 7'd0;
+ command <= #1 20'd0;
+ end
+ else if(start)
+ begin
+ counter <= #1 7'd1;
+ command <= #1 {read,w,addr_data};
+ end
+ else if( |counter && ~done )
+ begin
+ counter <= #1 counter + 7'd1;
+ if(~counter[0])
+ command <= {command[22:0],1'b0};
+ end
+
+
+ assign sen = (done | counter == 8'd0); // CSB is high when we're not doing anything
+ assign sclk = ~counter[0];
+ assign sdo = command[23];
+
+endmodule // clock_control
diff --git a/fpga/usrp2/control_lib/clock_control_tb.v b/fpga/usrp2/control_lib/clock_control_tb.v
new file mode 100644
index 000000000..9760efbe3
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_control_tb.v
@@ -0,0 +1,52 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module clock_control_tb();
+
+ clock_control clock_control
+ (.reset(reset),
+ .aux_clk(aux_clk),
+ .clk_fpga(clk_fpga),
+ .clk_en(clk_en),
+ .clk_sel(clk_sel),
+ .clk_func(clk_func),
+ .clk_status(clk_status),
+
+ .sen(sen),
+ .sclk(sclk),
+ .sdi(sdi),
+ .sdo(sdo)
+ );
+
+ reg reset, aux_clk;
+
+ wire [1:0] clk_sel, clk_en;
+
+ initial reset = 1'b1;
+ initial #1000 reset = 1'b0;
+
+ initial aux_clk = 1'b0;
+ always #10 aux_clk = ~aux_clk;
+
+ initial $dumpfile("clock_control_tb.vcd");
+ initial $dumpvars(0,clock_control_tb);
+
+ initial #10000 $finish;
+
+endmodule // clock_control_tb
diff --git a/fpga/usrp2/control_lib/cmdfile b/fpga/usrp2/control_lib/cmdfile
new file mode 100644
index 000000000..cb3756cfc
--- /dev/null
+++ b/fpga/usrp2/control_lib/cmdfile
@@ -0,0 +1,18 @@
+# My stuff
+-y .
+-y ../u2_basic
+-y ../control_lib
+-y ../sdr_lib
+
+# Models
+-y ../models
+
+# Open Cores
+-y ../opencores/spi/rtl/verilog
++incdir+../opencores/spi/rtl/verilog
+-y ../opencores/wb_conbus/rtl/verilog
++incdir+../opencores/wb_conbus/rtl/verilog
+-y ../opencores/i2c/rtl/verilog
++incdir+../opencores/i2c/rtl/verilog
+-y ../opencores/aemb/rtl/verilog
+-y ../opencores/simple_gpio/rtl
diff --git a/fpga/usrp2/control_lib/dbsm.v b/fpga/usrp2/control_lib/dbsm.v
new file mode 100644
index 000000000..fea51096f
--- /dev/null
+++ b/fpga/usrp2/control_lib/dbsm.v
@@ -0,0 +1,164 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module dbsm
+ (input clk,
+ input reset,
+ input clear,
+
+ output write_ok,
+ output write_ptr,
+ input write_done,
+
+ output read_ok,
+ output read_ptr,
+ input read_done,
+
+ output access_ok,
+ output access_ptr,
+ input access_done,
+ input access_skip_read
+ );
+
+ localparam PORT_WAIT_0 = 0;
+ localparam PORT_USE_0 = 1;
+ localparam PORT_WAIT_1 = 2;
+ localparam PORT_USE_1 = 3;
+
+ reg [1:0] write_port_state, access_port_state, read_port_state;
+
+ localparam BUFF_WRITABLE = 0;
+ localparam BUFF_ACCESSIBLE = 1;
+ localparam BUFF_READABLE = 2;
+ localparam BUFF_ERROR = 3;
+
+ wire [1:0] buff_state[0:1];
+
+ always @(posedge clk)
+ if(reset | clear)
+ write_port_state <= PORT_WAIT_0;
+ else
+ case(write_port_state)
+ PORT_WAIT_0 :
+ if(buff_state[0]==BUFF_WRITABLE)
+ write_port_state <= PORT_USE_0;
+ PORT_USE_0 :
+ if(write_done)
+ write_port_state <= PORT_WAIT_1;
+ PORT_WAIT_1 :
+ if(buff_state[1]==BUFF_WRITABLE)
+ write_port_state <= PORT_USE_1;
+ PORT_USE_1 :
+ if(write_done)
+ write_port_state <= PORT_WAIT_0;
+ endcase // case (write_port_state)
+
+ assign write_ok = (write_port_state == PORT_USE_0) | (write_port_state == PORT_USE_1);
+ assign write_ptr = (write_port_state == PORT_USE_1);
+
+ always @(posedge clk)
+ if(reset | clear)
+ access_port_state <= PORT_WAIT_0;
+ else
+ case(access_port_state)
+ PORT_WAIT_0 :
+ if(buff_state[0]==BUFF_ACCESSIBLE)
+ access_port_state <= PORT_USE_0;
+ PORT_USE_0 :
+ if(access_done)
+ access_port_state <= PORT_WAIT_1;
+ PORT_WAIT_1 :
+ if(buff_state[1]==BUFF_ACCESSIBLE)
+ access_port_state <= PORT_USE_1;
+ PORT_USE_1 :
+ if(access_done)
+ access_port_state <= PORT_WAIT_0;
+ endcase // case (access_port_state)
+
+ assign access_ok = (access_port_state == PORT_USE_0) | (access_port_state == PORT_USE_1);
+ assign access_ptr = (access_port_state == PORT_USE_1);
+
+ always @(posedge clk)
+ if(reset | clear)
+ read_port_state <= PORT_WAIT_0;
+ else
+ case(read_port_state)
+ PORT_WAIT_0 :
+ if(buff_state[0]==BUFF_READABLE)
+ read_port_state <= PORT_USE_0;
+ PORT_USE_0 :
+ if(read_done)
+ read_port_state <= PORT_WAIT_1;
+ PORT_WAIT_1 :
+ if(buff_state[1]==BUFF_READABLE)
+ read_port_state <= PORT_USE_1;
+ PORT_USE_1 :
+ if(read_done)
+ read_port_state <= PORT_WAIT_0;
+ endcase // case (read_port_state)
+
+ assign read_ok = (read_port_state == PORT_USE_0) | (read_port_state == PORT_USE_1);
+ assign read_ptr = (read_port_state == PORT_USE_1);
+
+ buff_sm #(.PORT_USE_FLAG(PORT_USE_0)) buff0_sm
+ (.clk(clk), .reset(reset), .clear(clear),
+ .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done),
+ .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state),
+ .buff_state(buff_state[0]));
+
+ buff_sm #(.PORT_USE_FLAG(PORT_USE_1)) buff1_sm
+ (.clk(clk), .reset(reset), .clear(clear),
+ .write_done(write_done), .access_done(access_done), .access_skip_read(access_skip_read), .read_done(read_done),
+ .write_port_state(write_port_state), .access_port_state(access_port_state), .read_port_state(read_port_state),
+ .buff_state(buff_state[1]));
+
+endmodule // dbsm
+
+module buff_sm
+ #(parameter PORT_USE_FLAG=0)
+ (input clk, input reset, input clear,
+ input write_done, input access_done, input access_skip_read, input read_done,
+ input [1:0] write_port_state, input [1:0] access_port_state, input [1:0] read_port_state,
+ output reg [1:0] buff_state);
+
+ localparam BUFF_WRITABLE = 0;
+ localparam BUFF_ACCESSIBLE = 1;
+ localparam BUFF_READABLE = 2;
+ localparam BUFF_ERROR = 3;
+
+ always @(posedge clk)
+ if(reset | clear)
+ buff_state <= BUFF_WRITABLE;
+ else
+ case(buff_state)
+ BUFF_WRITABLE :
+ if(write_done & (write_port_state == PORT_USE_FLAG))
+ buff_state <= BUFF_ACCESSIBLE;
+ BUFF_ACCESSIBLE :
+ if(access_done & (access_port_state == PORT_USE_FLAG))
+ if(access_skip_read)
+ buff_state <= BUFF_WRITABLE;
+ else
+ buff_state <= BUFF_READABLE;
+ BUFF_READABLE :
+ if(read_done & (read_port_state == PORT_USE_FLAG))
+ buff_state <= BUFF_WRITABLE;
+ BUFF_ERROR :
+ ;
+ endcase
+
+endmodule // buff_sm
diff --git a/fpga/usrp2/control_lib/dcache.v b/fpga/usrp2/control_lib/dcache.v
new file mode 100644
index 000000000..384c5a149
--- /dev/null
+++ b/fpga/usrp2/control_lib/dcache.v
@@ -0,0 +1,182 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module dcache
+ #(parameter AWIDTH=14,
+ parameter CWIDTH=6)
+ (input wb_clk_i,
+ input wb_rst_i,
+
+ input [AWIDTH-1:0] dwb_adr_i,
+ input dwb_stb_i,
+ input dwb_we_i,
+ input [3:0] dwb_sel_i,
+ input [31:0] dwb_dat_i,
+ output [31:0] dwb_dat_o,
+ output dwb_ack_o,
+
+ input [31:0] dram_dat_i,
+ output [31:0] dram_dat_o,
+ output [AWIDTH-1:0] dram_adr_o,
+ output dram_we_o,
+ output dram_en_o,
+ output [3:0] dram_sel_o );
+
+ localparam TAGWIDTH = AWIDTH-CWIDTH-2;
+ reg stb_d1, ack_d1, miss_d1;
+ reg [AWIDTH-1:0] held_addr;
+ reg [31:0] ddata [0:(1<<CWIDTH)-1];
+ reg [TAGWIDTH-1:0] dtags [0:(1<<CWIDTH)-1];
+ reg dvalid [0:(1<<CWIDTH)-1];
+
+ wire [CWIDTH-1:0] rd_line, wr_line;
+ wire [TAGWIDTH-1:0] wr_tags;
+ wire cache_write, invalidate;
+ wire [31:0] wr_data;
+
+ // /////////////////////////////////////
+ // Write into cache
+ integer i;
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ for(i=0;i<(1<<CWIDTH);i=i+1)
+ dvalid[i] <= 0;
+ else
+ if(invalidate)
+ dvalid[wr_line] <= 1'b0;
+ else if(cache_write)
+ dvalid[wr_line] <= 1'b1;
+
+ always @(posedge wb_clk_i)
+ if(cache_write)
+ begin
+ ddata[wr_line] <= wr_data;
+ dtags[wr_line] <= wr_tags;
+ end
+
+ // //////////////////////////////////////
+ // Read from Cache
+ wire [TAGWIDTH-1:0] tag_out = dtags[rd_line];
+ wire valid_out = dvalid[rd_line];
+ wire [31:0] data_out = ddata[rd_line];
+ wire cache_hit = valid_out & (tag_out == dwb_adr_i[AWIDTH-1:CWIDTH+2]);
+ wire cache_miss = ~cache_hit;
+
+ // //////////////////////////////////////
+ // Handle 1-cycle delay of Block-RAM
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ stb_d1 <= 0;
+ else
+ stb_d1 <= dwb_stb_i;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ held_addr <= 0;
+ else
+ held_addr <= dwb_adr_i;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ ack_d1 <= 1'b0;
+ else
+ ack_d1 <= dwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ miss_d1 <= 0;
+ else
+ miss_d1 <= cache_miss;
+
+`define DC_NOCACHE
+//`define DC_BASIC
+//`define DC_FORWARDING_DP
+//`define DC_FORWARDING_SP
+//`define DC_PREFETCH
+
+`ifdef DC_NOCACHE
+ assign dwb_dat_o = dram_dat_i;
+ assign dwb_ack_o = dwb_stb_i & (dwb_we_i | (stb_d1 & ~ack_d1));
+ assign dram_adr_o = dwb_adr_i;
+ assign dram_en_o = dwb_stb_i;
+ assign dram_dat_o = dwb_dat_i;
+ assign dram_we_o = dwb_we_i;
+ assign dram_sel_o = dwb_sel_i;
+ assign rd_line = 0;
+ assign wr_line = 0;
+ assign wr_tags = 0;
+ assign wr_data = 0;
+ assign cache_write = 0;
+ assign invalidate = 0;
+`endif
+
+`ifdef DC_BASIC // Very basic, no forwarding, 2 wait states on miss
+ assign dwb_dat_o = data_out;
+ assign dwb_ack_o = dwb_stb_i & cache_hit;
+ assign dram_adr_o = dwb_adr_i;
+ assign dram_en_o = dwb_stb_i;
+ assign dram_dat_o = dwb_dat_i;
+ assign dram_we_o = dwb_we_i;
+ assign dram_sel_o = dwb_sel_i;
+ assign rd_line = dwb_adr_i[CWIDTH+1:2];
+ assign wr_line = rd_line;
+ assign wr_tags = dwb_adr_i[AWIDTH-1:CWIDTH+2];
+ assign wr_data = dwb_we_i ? dwb_dat_i : dram_dat_i;
+ assign cache_write = dwb_stb_i & (dwb_we_i | (stb_d1 & miss_d1));
+ assign invalidate = dwb_we_i & ~(&dwb_sel_i);
+`endif
+
+`ifdef DC_FORWARDING_DP // Simple forwarding, 1 wait state on miss, dual-port ram
+ assign dwb_dat_o = cache_hit ? data_out : dram_dat_i;
+ assign dwb_ack_o = dwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1));
+ assign dram_adr_o = dwb_adr_i;
+ assign dram_en_o = 1'b1;
+ assign dram_dat_o = dwb_dat_i;
+ assign dram_we_o = dwb_we_i;
+ assign dram_sel_o = dwb_sel_i;
+ assign rd_line = dwb_adr_i[CWIDTH+1:2];
+ assign wr_line = held_addr[CWIDTH+1:2];
+ assign wr_tags = held_addr[AWIDTH-1:CWIDTH+2];
+ assign wr_data = dram_dat_i;
+ assign cache_write = dwb_stb_i & stb_d1 & miss_d1 & ~ack_d1;
+ assign invalidate = 0;
+`endif
+
+`ifdef DC_FORWARDING_SP // Simple forwarding, 1 wait state on miss, single-port ram
+ assign dwb_dat_o = cache_hit ? data_out : dram_dat_i;
+ assign dwb_ack_o = dwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1));
+ assign dram_adr_o = dwb_adr_i;
+ assign dram_en_o = 1'b1;
+ assign dram_dat_o = dwb_dat_i;
+ assign dram_we_o = dwb_we_i;
+ assign dram_sel_o = dwb_sel_i;
+ assign rd_line = dwb_adr_i[CWIDTH+1:2];
+ assign wr_line = rd_line;
+ assign wr_tags = dwb_adr_i[AWIDTH-1:CWIDTH+2];
+ assign wr_data = dram_dat_i;
+ assign cache_write = dwb_stb_i & stb_d1 & miss_d1 & ~ack_d1;
+ assign invalidate = 0;
+`endif
+
+`ifdef DC_PREFETCH // Forwarding plus prefetch
+
+`endif
+
+
+endmodule // dcache
+
diff --git a/fpga/usrp2/control_lib/decoder_3_8.v b/fpga/usrp2/control_lib/decoder_3_8.v
new file mode 100644
index 000000000..8f91d8263
--- /dev/null
+++ b/fpga/usrp2/control_lib/decoder_3_8.v
@@ -0,0 +1,38 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module decoder_3_8
+ (input [2:0] sel,
+ output reg [7:0] res);
+
+ always @(sel or res)
+ begin
+ case (sel)
+ 3'b000 : res = 8'b00000001;
+ 3'b001 : res = 8'b00000010;
+ 3'b010 : res = 8'b00000100;
+ 3'b011 : res = 8'b00001000;
+ 3'b100 : res = 8'b00010000;
+ 3'b101 : res = 8'b00100000;
+ 3'b110 : res = 8'b01000000;
+ default : res = 8'b10000000;
+ endcase // case(sel)
+ end // always @ (sel or res)
+
+endmodule // decoder_3_8
+
diff --git a/fpga/usrp2/control_lib/double_buffer.v b/fpga/usrp2/control_lib/double_buffer.v
new file mode 100644
index 000000000..8865bddee
--- /dev/null
+++ b/fpga/usrp2/control_lib/double_buffer.v
@@ -0,0 +1,139 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module double_buffer
+ #(parameter BUF_SIZE = 9)
+ (input clk, input reset, input clear,
+
+ // Random access interface to RAM
+ input access_we,
+ input access_stb,
+ output access_ok,
+ input access_done,
+ input access_skip_read,
+ input [BUF_SIZE-1:0] access_adr,
+ output [BUF_SIZE-1:0] access_len,
+ input [35:0] access_dat_i,
+ output [35:0] access_dat_o,
+
+ // Write FIFO Interface
+ input [35:0] data_i,
+ input src_rdy_i,
+ output dst_rdy_o,
+
+ // Read FIFO Interface
+ output [35:0] data_o,
+ output src_rdy_o,
+ input dst_rdy_i
+ );
+
+ wire [35:0] data_o_0, data_o_1;
+
+ wire read, read_ok, read_ptr, read_done;
+ wire write, write_ok, write_ptr, write_done;
+
+ wire [BUF_SIZE-1:0] rw0_adr, rw1_adr;
+ reg [BUF_SIZE-1:0] read_adr, write_adr;
+ reg [BUF_SIZE-1:0] len0, len1;
+
+ assign data_o = read_ptr ? data_o_1 : data_o_0;
+ assign rw0_adr = (write_ok & ~write_ptr) ? write_adr : read_adr;
+ assign rw1_adr = (write_ok & write_ptr) ? write_adr : read_adr;
+
+ wire [35:0] access_dat_o_0, access_dat_o_1;
+ wire access_ptr;
+ assign access_dat_o = access_ptr? access_dat_o_1 : access_dat_o_0;
+
+ dbsm dbsm
+ (.clk(clk), .reset(reset), .clear(clear),
+ .write_ok(write_ok), .write_ptr(write_ptr), .write_done(write_done),
+ .access_ok(access_ok), .access_ptr(access_ptr), .access_done(access_done), .access_skip_read(access_skip_read),
+ .read_ok(read_ok), .read_ptr(read_ptr), .read_done(read_done));
+
+ // Port A for random access, Port B for FIFO read and write
+ ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer0
+ (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 0)),.wea(access_we),
+ .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_0),
+ .clkb(clk),.enb((read & read_ok & ~read_ptr)|(write & write_ok & ~write_ptr) ),.web(write&write_ok&~write_ptr),
+ .addrb(rw0_adr),.dib(data_i),.dob(data_o_0));
+
+ ram_2port #(.DWIDTH(36),.AWIDTH(BUF_SIZE)) buffer1
+ (.clka(clk),.ena(access_stb & access_ok & (access_ptr == 1)),.wea(access_we),
+ .addra(access_adr),.dia(access_dat_i),.doa(access_dat_o_1),
+ .clkb(clk),.enb((read & read_ok & read_ptr)|(write & write_ok & write_ptr) ),.web(write&write_ok&write_ptr),
+ .addrb(rw1_adr),.dib(data_i),.dob(data_o_1));
+
+ // Write into buffers
+ assign dst_rdy_o = write_ok;
+ assign write = src_rdy_i & write_ok;
+ assign write_done = write & data_i[33]; // done
+ always @(posedge clk)
+ if(reset | clear)
+ write_adr <= 0;
+ else
+ if(write_done)
+ begin
+ write_adr <= 0;
+ if(write_ptr)
+ len1 <= write_adr + 1;
+ else
+ len0 <= write_adr + 1;
+ end
+ else if(write)
+ write_adr <= write_adr + 1;
+
+ assign access_len = access_ptr ? len1 : len0;
+
+ reg [1:0] read_state;
+ localparam IDLE = 0;
+ localparam PRE_READ = 1;
+ localparam READING = 2;
+
+ always @(posedge clk)
+ if(reset | clear)
+ begin
+ read_state <= IDLE;
+ read_adr <= 0;
+ end
+ else
+ case(read_state)
+ IDLE :
+ begin
+ read_adr <= 0;
+ if(read_ok)
+ read_state <= PRE_READ;
+ end
+ PRE_READ :
+ begin
+ read_state <= READING;
+ read_adr <= 1;
+ end
+
+ READING :
+ if(dst_rdy_i)
+ begin
+ read_adr <= read_adr + 1;
+ if(data_o[33])
+ read_state <= IDLE;
+ end
+ endcase // case (read_state)
+
+ assign read = ~((read_state==READING)& ~dst_rdy_i);
+ assign read_done = data_o[33] & dst_rdy_i & src_rdy_o;
+ assign src_rdy_o = (read_state == READING);
+
+endmodule // double_buffer
diff --git a/fpga/usrp2/control_lib/double_buffer_tb.v b/fpga/usrp2/control_lib/double_buffer_tb.v
new file mode 100644
index 000000000..804e8804d
--- /dev/null
+++ b/fpga/usrp2/control_lib/double_buffer_tb.v
@@ -0,0 +1,312 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module double_buffer_tb();
+
+ reg clk = 0;
+ reg rst = 1;
+ reg clear = 0;
+ initial #1000 rst = 0;
+ always #50 clk = ~clk;
+
+ wire src_rdy_o;
+ reg src_rdy_i = 0;
+ wire dst_rdy_o;
+
+ wire dst_rdy_i = 0;
+ wire [35:0] data_o;
+ reg [35:0] data_i;
+
+ wire access_we, access_stb, access_done, access_ok, access_skip_read;
+
+ wire [8:0] access_adr, access_len;
+ wire [35:0] dsp_to_buf, buf_to_dsp;
+ reg set_stb = 0;
+
+ double_buffer db
+ (.clk(clk),.reset(rst),.clear(0),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(dsp_to_buf), .access_dat_o(buf_to_dsp),
+
+ .data_i(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
+ .data_o(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+
+ dspengine_8to16 #(.HEADER_OFFSET(1)) dspengine_8to16
+ (.clk(clk),.reset(rst),.clear(0),
+ .set_stb(set_stb), .set_addr(0), .set_data(1),
+ .access_we(access_we), .access_stb(access_stb), .access_ok(access_ok), .access_done(access_done),
+ .access_skip_read(access_skip_read), .access_adr(access_adr), .access_len(access_len),
+ .access_dat_i(buf_to_dsp), .access_dat_o(dsp_to_buf));
+
+ always @(posedge clk)
+ if(src_rdy_o & dst_rdy_i)
+ begin
+ $display("SOF %d, EOF %d, OCC %x, DAT %x",data_o[32],data_o[33],data_o[35:34],data_o[31:0]);
+ if(data_o[33])
+ $display();
+ end
+ initial $dumpfile("double_buffer_tb.vcd");
+ initial $dumpvars(0,double_buffer_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+/*
+ // Passthrough
+ $display("Passthrough");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'h01234567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hFFFFFFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h04050607};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h08090a0b};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h0c0d0e0f};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ repeat (5)
+ @(posedge clk);
+*/
+ $display("Enabled");
+ set_stb <= 1;
+ @(posedge clk);
+ set_stb <= 0;
+/*
+ @(posedge clk);
+ $display("Non-IF Data Passthrough");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'h89acdef0};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hC0000000};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h14151617};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h18191a1b};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h1c1d1e1f};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ while(~dst_rdy_o)
+ @(posedge clk);
+
+ $display("No StreamID, No Trailer, Even");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hAAAAAAAA};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h01000200};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h03000400};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h05000600};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h07000800};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h09000a00};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h0b000c00};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ while(~dst_rdy_o)
+ @(posedge clk);
+
+ $display("No StreamID, No Trailer, Odd");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hBBBBBBBB};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0000FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h11001200};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h13001400};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h15001600};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h17001800};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h19001a00};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ while(~dst_rdy_o)
+ @(posedge clk);
+*/
+ /*
+ $display("No StreamID, Trailer, Even");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hCCCCCCCC};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hDEADBEEF};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+*/
+ while(~dst_rdy_o)
+ @(posedge clk);
+/*
+ $display("No StreamID, Trailer, Odd");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hDDDDDDDD};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h0400FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h21222324};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h25262728};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h292a2b2c};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h2d2e2f30};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hDEBDBF0D};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+*/
+ while(~dst_rdy_o)
+ @(posedge clk);
+
+/*
+ $display("No StreamID, Trailer, Odd");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'h0400FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h31003200};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h33003400};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h35003600};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h39003a00};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ while(~dst_rdy_o)
+ @(posedge clk);
+
+ $display("StreamID, No Trailer, Even");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'h1000FFFF};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h11001200};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h13001400};
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h15001600};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h17001800};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'h19001a00};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ while(~dst_rdy_o)
+ @(posedge clk);
+*/
+ $display("StreamID, Trailer, Odd");
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
+// src_rdy_i <= 0;
+// @(posedge clk);
+// src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+ src_rdy_i <= 1;
+ data_i <= { 2'b00,1'b0,1'b1,32'hABCDEF98};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'h1c034567};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha0a1a2a3};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha4a5a6a7};
+// src_rdy_i <= 0;
+// @(posedge clk);
+// src_rdy_i <= 1;
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'ha8a9aaab};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b0,1'b0,32'hacadaeaf};
+ @(posedge clk);
+ data_i <= { 2'b00,1'b1,1'b0,32'hdeadbeef};
+ @(posedge clk);
+ src_rdy_i <= 0;
+ @(posedge clk);
+
+ end
+
+ initial #28000 $finish;
+endmodule // double_buffer_tb
diff --git a/fpga/usrp2/control_lib/dpram32.v b/fpga/usrp2/control_lib/dpram32.v
new file mode 100644
index 000000000..386435e70
--- /dev/null
+++ b/fpga/usrp2/control_lib/dpram32.v
@@ -0,0 +1,99 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Dual ported RAM
+// Addresses are byte-oriented, so botton 2 address bits are ignored.
+// AWIDTH of 13 allows you to address 8K bytes.
+// For Spartan 3, if the total RAM size is not a multiple of 8K then BRAM space is wasted
+// RAM_SIZE parameter allows odd-sized RAMs, like 24K
+
+module dpram32 #(parameter AWIDTH=15,
+ parameter RAM_SIZE=16384)
+ (input clk,
+
+ input [AWIDTH-1:0] adr1_i,
+ input [31:0] dat1_i,
+ output reg [31:0] dat1_o,
+ input we1_i,
+ input en1_i,
+ input [3:0] sel1_i,
+
+ input [AWIDTH-1:0] adr2_i,
+ input [31:0] dat2_i,
+ output reg [31:0] dat2_o,
+ input we2_i,
+ input en2_i,
+ input [3:0] sel2_i );
+
+ reg [7:0] ram0 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram1 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram2 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram3 [0:(RAM_SIZE/4)-1];
+
+ // This is how we used to size the RAM -->
+ // reg [7:0] ram3 [0:(1<<(AWIDTH-2))-1];
+
+ // Port 1
+ always @(posedge clk)
+ if(en1_i) dat1_o[31:24] <= ram3[adr1_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en1_i) dat1_o[23:16] <= ram2[adr1_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en1_i) dat1_o[15:8] <= ram1[adr1_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en1_i) dat1_o[7:0] <= ram0[adr1_i[AWIDTH-1:2]];
+
+ always @(posedge clk)
+ if(we1_i & en1_i & sel1_i[3])
+ ram3[adr1_i[AWIDTH-1:2]] <= dat1_i[31:24];
+ always @(posedge clk)
+ if(we1_i & en1_i & sel1_i[2])
+ ram2[adr1_i[AWIDTH-1:2]] <= dat1_i[23:16];
+ always @(posedge clk)
+ if(we1_i & en1_i & sel1_i[1])
+ ram1[adr1_i[AWIDTH-1:2]] <= dat1_i[15:8];
+ always @(posedge clk)
+ if(we1_i & en1_i & sel1_i[0])
+ ram0[adr1_i[AWIDTH-1:2]] <= dat1_i[7:0];
+
+ // Port 2
+ always @(posedge clk)
+ if(en2_i) dat2_o[31:24] <= ram3[adr2_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en2_i) dat2_o[23:16] <= ram2[adr2_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en2_i) dat2_o[15:8] <= ram1[adr2_i[AWIDTH-1:2]];
+ always @(posedge clk)
+ if(en2_i) dat2_o[7:0] <= ram0[adr2_i[AWIDTH-1:2]];
+
+ always @(posedge clk)
+ if(we2_i & en2_i & sel2_i[3])
+ ram3[adr2_i[AWIDTH-1:2]] <= dat2_i[31:24];
+ always @(posedge clk)
+ if(we2_i & en2_i & sel2_i[2])
+ ram2[adr2_i[AWIDTH-1:2]] <= dat2_i[23:16];
+ always @(posedge clk)
+ if(we2_i & en2_i & sel2_i[1])
+ ram1[adr2_i[AWIDTH-1:2]] <= dat2_i[15:8];
+ always @(posedge clk)
+ if(we2_i & en2_i & sel2_i[0])
+ ram0[adr2_i[AWIDTH-1:2]] <= dat2_i[7:0];
+
+endmodule // dpram32
+
+
diff --git a/fpga/usrp2/control_lib/fifo_to_wb.v b/fpga/usrp2/control_lib/fifo_to_wb.v
new file mode 100644
index 000000000..9b6b5e804
--- /dev/null
+++ b/fpga/usrp2/control_lib/fifo_to_wb.v
@@ -0,0 +1,183 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module fifo_to_wb
+ #(parameter PKT_LEN = 16)
+ (input clk, input reset, input clear,
+ input [18:0] data_i, input src_rdy_i, output dst_rdy_o,
+ output [18:0] data_o, output src_rdy_o, input dst_rdy_i,
+ output reg [15:0] wb_adr_o, output [15:0] wb_dat_mosi, input [15:0] wb_dat_miso,
+ output [1:0] wb_sel_o, output wb_cyc_o, output wb_stb_o, output wb_we_o, input wb_ack_i,
+ input [7:0] triggers,
+ output [31:0] debug0, output [31:0] debug1);
+
+ wire [18:0] ctrl_data;
+ reg [18:0] resp_data;
+ wire ctrl_src_rdy, ctrl_dst_rdy, resp_src_rdy, resp_dst_rdy;
+
+ fifo_short #(.WIDTH(19)) ctrl_sfifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(data_i), .src_rdy_i(src_rdy_i), .dst_rdy_o(dst_rdy_o),
+ .dataout(ctrl_data), .src_rdy_o(ctrl_src_rdy), .dst_rdy_i(ctrl_dst_rdy));
+
+ fifo_short #(.WIDTH(19)) resp_sfifo
+ (.clk(clk), .reset(reset), .clear(clear),
+ .datain(resp_data), .src_rdy_i(resp_src_rdy), .dst_rdy_o(resp_dst_rdy),
+ .dataout(data_o), .src_rdy_o(src_rdy_o), .dst_rdy_i(dst_rdy_i));
+
+ // Need a programmable state machine here. The program is the fifo contents.
+ // All words are 16 bits wide
+ // Word 0 Command { Read, Write, Triggers[5:0], Seqno [7:0] }
+ // Word 1 Length
+ // Word 2 Address LSW
+ // Word 3 Address MSW (should all be 0)
+
+ localparam RESP_IDLE = 0;
+ localparam RESP_LEN = 1;
+ localparam RESP_ADDR_LSW = 2;
+ localparam RESP_ADDR_MSW = 3;
+ localparam RESP_WRITE = 4;
+ localparam RESP_DUMP = 5;
+ localparam RESP_WAIT_READ = 6;
+ localparam RESP_RCMD = 7;
+ localparam RESP_RLEN = 8;
+ localparam RESP_RADDR_LSW = 9;
+ localparam RESP_RADDR_MSW = 10;
+ localparam RESP_READ = 11;
+
+ reg [3:0] resp_state;
+ reg rd, wr;
+ reg [15:0] base_addr;
+ reg [15:0] length;
+ reg [15:0] count;
+ reg [7:0] seqnum;
+ reg [5:0] which_trig;
+
+ always @(posedge clk)
+ if(reset | clear)
+ resp_state <= RESP_IDLE;
+ else
+ case(resp_state)
+ RESP_IDLE :
+ if(ctrl_src_rdy)
+ begin
+ { rd, wr, which_trig[5:0], seqnum[7:0] } <= ctrl_data[15:0];
+ if(ctrl_data[16]) // WAIT for start of packet, clean out otherwise
+ resp_state <= RESP_LEN;
+ end
+ RESP_LEN :
+ if(ctrl_src_rdy)
+ begin
+ length <= ctrl_data[15:0];
+ count <= ctrl_data[15:0];
+ resp_state <= RESP_ADDR_LSW;
+ end
+ RESP_ADDR_LSW :
+ if(ctrl_src_rdy)
+ begin
+ base_addr <= ctrl_data[15:0];
+ wb_adr_o <= ctrl_data[15:0];
+ resp_state <= RESP_ADDR_MSW;
+ end
+ RESP_ADDR_MSW :
+ if(ctrl_src_rdy)
+ if(wr)
+ resp_state <= RESP_WRITE;
+ else
+ resp_state <= RESP_DUMP;
+ RESP_WRITE :
+ if(ctrl_src_rdy & wb_ack_i)
+ if(count==1)
+ if(ctrl_data[17]) //eof
+ resp_state <= RESP_IDLE;
+ else // clean out padding
+ resp_state <= RESP_DUMP;
+ else
+ begin
+ wb_adr_o <= wb_adr_o + 2;
+ count <= count - 1;
+ end
+ RESP_DUMP :
+ if(ctrl_src_rdy & ctrl_data[17])
+ if(rd)
+ resp_state <= RESP_WAIT_READ;
+ else
+ resp_state <= RESP_IDLE;
+ RESP_WAIT_READ :
+ begin
+ wb_adr_o <= base_addr;
+ count <= length;
+ if( &(triggers | ~which_trig) )
+ resp_state <= RESP_RCMD;
+ end
+ RESP_RCMD :
+ if(resp_dst_rdy)
+ resp_state <= RESP_RLEN;
+ RESP_RLEN :
+ if(resp_dst_rdy)
+ resp_state <= RESP_RADDR_LSW;
+ RESP_RADDR_LSW :
+ if(resp_dst_rdy)
+ resp_state <= RESP_RADDR_MSW;
+ RESP_RADDR_MSW :
+ if(resp_dst_rdy)
+ resp_state <= RESP_READ;
+ RESP_READ :
+ if(resp_dst_rdy & wb_ack_i)
+ if(count==1)
+ resp_state <= RESP_IDLE;
+ else
+ begin
+ wb_adr_o <= wb_adr_o + 2;
+ count <= count - 1;
+ end
+ endcase // case (resp_state)
+
+ always @*
+ case(resp_state)
+ RESP_RCMD : resp_data <= { 3'b001, 8'hAA, seqnum };
+ RESP_RLEN : resp_data <= { 3'b000, length };
+ RESP_RADDR_LSW : resp_data <= { 3'b000, base_addr };
+ RESP_RADDR_MSW : resp_data <= { 3'b000, 16'd0 };
+ default : resp_data <= { 1'b0, (count==1), 1'b0, wb_dat_miso };
+ endcase // case (resp_state)
+
+ assign ctrl_dst_rdy = (resp_state == RESP_IDLE) |
+ (resp_state == RESP_LEN) |
+ (resp_state == RESP_ADDR_LSW) |
+ (resp_state == RESP_ADDR_MSW) |
+ ((resp_state == RESP_WRITE) & wb_ack_i) |
+ (resp_state == RESP_DUMP);
+
+ assign resp_src_rdy = (resp_state == RESP_RCMD) |
+ (resp_state == RESP_RLEN) |
+ (resp_state == RESP_RADDR_LSW) |
+ (resp_state == RESP_RADDR_MSW) |
+ ((resp_state == RESP_READ) & wb_ack_i);
+
+ assign wb_dat_mosi = ctrl_data[15:0];
+ assign wb_we_o = (resp_state == RESP_WRITE);
+ assign wb_cyc_o = wb_stb_o;
+ assign wb_sel_o = 2'b11;
+ assign wb_stb_o = (ctrl_src_rdy & (resp_state == RESP_WRITE)) | (resp_dst_rdy & (resp_state == RESP_READ));
+
+
+ assign debug0 = { 14'd0, ctrl_data[17:0] };
+ assign debug1 = { ctrl_src_rdy, ctrl_dst_rdy, resp_src_rdy, resp_dst_rdy, 2'b00, ctrl_data[17:16] };
+
+endmodule // fifo_to_wb
diff --git a/fpga/usrp2/control_lib/fifo_to_wb_tb.v b/fpga/usrp2/control_lib/fifo_to_wb_tb.v
new file mode 100644
index 000000000..37459e2c2
--- /dev/null
+++ b/fpga/usrp2/control_lib/fifo_to_wb_tb.v
@@ -0,0 +1,136 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module fifo_to_wb_tb();
+
+ reg clk = 0;
+ reg rst = 1;
+ reg clear = 0;
+ initial #1000 rst = 0;
+ always #50 clk = ~clk;
+
+ reg trigger = 0;
+ initial #10000 trigger = 1;
+
+ wire wb_cyc, wb_stb, wb_we, wb_ack;
+ wire [15:0] wb_adr;
+ wire [15:0] wb_dat_miso, wb_dat_mosi;
+
+ reg cmd_src_rdy;
+ wire cmd_dst_rdy, resp_src_rdy, resp_dst_rdy;
+ reg [17:0] cmd;
+ wire [17:0] resp;
+
+ wire [17:0] resp_int;
+ wire resp_src_rdy_int, resp_dst_rdy_int;
+
+ fifo_to_wb fifo_to_wb
+ (.clk(clk), .reset(rst), .clear(clear),
+ .data_i(cmd), .src_rdy_i(cmd_src_rdy), .dst_rdy_o(cmd_dst_rdy),
+ .data_o(resp_int), .src_rdy_o(resp_src_rdy_int), .dst_rdy_i(resp_dst_rdy_int),
+
+ .wb_adr_o(wb_adr), .wb_dat_mosi(wb_dat_mosi), .wb_dat_miso(wb_dat_miso),
+ .wb_sel_o(), .wb_cyc_o(wb_cyc), .wb_stb_o(wb_stb),
+ .wb_we_o(wb_we), .wb_ack_i(wb_ack),
+ .triggers());
+
+ assign wb_dat_miso = {wb_adr[7:0],8'hBF};
+
+ fifo19_pad #(.LENGTH(16)) fifo19_pad
+ (.clk(clk), .reset(rst), .clear(clear),
+ .data_i(resp_int), .src_rdy_i(resp_src_rdy_int), .dst_rdy_o(resp_dst_rdy_int),
+ .data_o(resp), .src_rdy_o(resp_src_rdy), .dst_rdy_i(resp_dst_rdy));
+
+
+ // Set up monitors
+ always @(posedge clk)
+ if(wb_cyc & wb_stb & wb_ack)
+ if(wb_we)
+ $display("WB-WRITE ADDR:%h DATA:%h",wb_adr, wb_dat_mosi);
+ else
+ $display("WB-READ ADDR:%h DATA:%h",wb_adr, wb_dat_miso);
+
+ always @(posedge clk)
+ if(cmd_src_rdy & cmd_dst_rdy)
+ $display("CMD-WRITE SOF:%b EOF:%b DATA:%h",cmd[16],cmd[17],cmd[15:0]);
+
+ always @(posedge clk)
+ if(resp_src_rdy & resp_dst_rdy)
+ $display("RESP-READ SOF:%b EOF:%b DATA:%h",resp[16],resp[17],resp[15:0]);
+
+ assign wb_ack = wb_stb;
+ assign resp_dst_rdy = 1;
+
+ task InsertRW;
+ input [15:0] data_start;
+ input [5:0] triggers;
+ input [7:0] seqno;
+ input [15:0] len;
+ input [15:0] addr;
+ reg [15:0] data_val;
+
+ begin
+ data_val <= data_start;
+ @(posedge clk);
+ cmd <= {2'b01,2'b11,triggers,seqno};
+ cmd_src_rdy <= 1;
+ @(posedge clk);
+ cmd <= {2'b00,len};
+ @(posedge clk);
+ cmd <= {2'b00,addr};
+ @(posedge clk);
+ cmd <= {2'b00,16'd0};
+ @(posedge clk);
+ repeat (len)
+ begin
+ cmd <= {2'b00,data_val};
+ data_val <= data_val + 1;
+ @(posedge clk);
+ end
+ repeat (12-len-1)
+ begin
+ cmd <= {2'b00,16'hBEEF};
+ @(posedge clk);
+ end
+ cmd <= {2'b10, 16'hDEAD};
+ @(posedge clk);
+ cmd_src_rdy <= 0;
+ end
+ endtask // InsertRead
+
+ initial $dumpfile("fifo_to_wb_tb.vcd");
+ initial $dumpvars(0,fifo_to_wb_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ //#10000;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ InsertRW(16'hF00D, 6'd0, 8'hB5, 16'd7, 16'h1234);
+ #20000;
+ InsertRW(16'h9876, 6'd0, 8'h43, 16'd8, 16'hBEEF);
+ #20000;
+ InsertRW(16'h1000, 6'd0, 8'h96, 16'd4, 16'hF00D);
+ #20000;
+ InsertRW(16'h3000, 6'd0, 8'h12, 16'd10,16'hDEAD);
+ #20000 $finish;
+ end
+
+endmodule // fifo_to_wb_tb
diff --git a/fpga/usrp2/control_lib/gpio_atr.v b/fpga/usrp2/control_lib/gpio_atr.v
new file mode 100644
index 000000000..82d72b815
--- /dev/null
+++ b/fpga/usrp2/control_lib/gpio_atr.v
@@ -0,0 +1,71 @@
+
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module gpio_atr
+ #(parameter BASE = 0,
+ parameter WIDTH = 32)
+ (input clk, input reset,
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+ input rx, input tx,
+ inout [WIDTH-1:0] gpio,
+ output reg [31:0] gpio_readback
+ );
+
+ wire [WIDTH-1:0] ddr, in_idle, in_tx, in_rx, in_fdx;
+ reg [WIDTH-1:0] rgpio, igpio;
+
+ setting_reg #(.my_addr(BASE+0), .width(WIDTH)) reg_idle
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_idle),.changed());
+
+ setting_reg #(.my_addr(BASE+1), .width(WIDTH)) reg_rx
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_rx),.changed());
+
+ setting_reg #(.my_addr(BASE+2), .width(WIDTH)) reg_tx
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_tx),.changed());
+
+ setting_reg #(.my_addr(BASE+3), .width(WIDTH)) reg_fdx
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(in_fdx),.changed());
+
+ setting_reg #(.my_addr(BASE+4), .width(WIDTH)) reg_ddr
+ (.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr), .in(set_data),
+ .out(ddr),.changed());
+
+ always @(posedge clk)
+ case({tx,rx})
+ 2'b00: rgpio <= in_idle;
+ 2'b01: rgpio <= in_rx;
+ 2'b10: rgpio <= in_tx;
+ 2'b11: rgpio <= in_fdx;
+ endcase // case ({tx,rx})
+
+ integer n;
+ always @*
+ for(n=0;n<WIDTH;n=n+1)
+ igpio[n] <= ddr[n] ? rgpio[n] : 1'bz;
+
+ assign gpio = igpio;
+
+ always @(posedge clk)
+ gpio_readback <= gpio;
+
+endmodule // gpio_atr
diff --git a/fpga/usrp2/control_lib/gray2bin.v b/fpga/usrp2/control_lib/gray2bin.v
new file mode 100644
index 000000000..399d5bba0
--- /dev/null
+++ b/fpga/usrp2/control_lib/gray2bin.v
@@ -0,0 +1,30 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module gray2bin
+ #(parameter WIDTH=8)
+ (input [WIDTH-1:0] gray,
+ output reg [WIDTH-1:0] bin);
+
+ integer i;
+ always @(gray)
+ for(i = 0;i<WIDTH;i=i+1)
+ bin[i] = ^(gray>>i);
+
+endmodule // gray2bin
diff --git a/fpga/usrp2/control_lib/gray_send.v b/fpga/usrp2/control_lib/gray_send.v
new file mode 100644
index 000000000..62402f8d3
--- /dev/null
+++ b/fpga/usrp2/control_lib/gray_send.v
@@ -0,0 +1,46 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+
+module gray_send
+ #(parameter WIDTH = 8)
+ (input clk_in, input [WIDTH-1:0] addr_in,
+ input clk_out, output reg [WIDTH-1:0] addr_out);
+
+ reg [WIDTH-1:0] gray_clkin, gray_clkout, gray_clkout_d1;
+ wire [WIDTH-1:0] gray, bin;
+
+ bin2gray #(.WIDTH(WIDTH)) b2g (.bin(addr_in), .gray(gray) );
+
+ always @(posedge clk_in)
+ gray_clkin <= gray;
+
+ always @(posedge clk_out)
+ gray_clkout <= gray_clkin;
+
+ always @(posedge clk_out)
+ gray_clkout_d1 <= gray_clkout;
+
+ gray2bin #(.WIDTH(WIDTH)) g2b (.gray(gray_clkout_d1), .bin(bin) );
+
+ // FIXME we may not need the next register, but it may help timing
+ always @(posedge clk_out)
+ addr_out <= bin;
+
+endmodule // gray_send
diff --git a/fpga/usrp2/control_lib/icache.v b/fpga/usrp2/control_lib/icache.v
new file mode 100644
index 000000000..810b5fa64
--- /dev/null
+++ b/fpga/usrp2/control_lib/icache.v
@@ -0,0 +1,152 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module icache
+ #(parameter AWIDTH=14,
+ parameter CWIDTH=6)
+
+ (input wb_clk_i,
+ input wb_rst_i,
+ input [AWIDTH-1:0] iwb_adr_i,
+ input iwb_stb_i,
+ output [31:0] iwb_dat_o,
+ output iwb_ack_o,
+ input [31:0] iram_dat_i,
+ output [AWIDTH-1:0] iram_adr_o,
+ output iram_en_o,
+ input flush);
+
+ localparam TAGWIDTH = AWIDTH-CWIDTH-2;
+ reg stb_d1, ack_d1, miss_d1;
+ reg [AWIDTH-1:0] held_addr;
+ reg [31:0] idata [0:(1<<CWIDTH)-1];
+ reg [TAGWIDTH-1:0] itags [0:(1<<CWIDTH)-1];
+ reg ivalid [0:(1<<CWIDTH)-1];
+
+ wire [CWIDTH-1:0] rd_line, wr_line;
+ wire [TAGWIDTH-1:0] wr_tags;
+ wire store_in_cache;
+
+ // /////////////////////////////////////
+ // Write into cache
+ integer i;
+ always @(posedge wb_clk_i)
+ if(wb_rst_i | flush)
+ for(i=0;i<(1<<CWIDTH);i=i+1)
+ ivalid[i] <= 0;
+ else
+ if(store_in_cache)
+ ivalid[wr_line] <= 1'b1;
+
+ always @(posedge wb_clk_i)
+ if(store_in_cache)
+ begin
+ idata[wr_line] <= iram_dat_i;
+ itags[wr_line] <= wr_tags;
+ end
+
+ // //////////////////////////////////////
+ // Read from Cache
+ wire [TAGWIDTH-1:0] tag_out = itags[rd_line];
+ wire valid_out = ivalid[rd_line];
+ wire [31:0] data_out = idata[rd_line];
+ wire cache_hit = valid_out & (tag_out == iwb_adr_i[AWIDTH-1:CWIDTH+2]);
+ wire cache_miss = ~cache_hit;
+
+ // //////////////////////////////////////
+ // Handle 1-cycle delay of Block-RAM
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ stb_d1 <= 0;
+ else
+ stb_d1 <= iwb_stb_i;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ held_addr <= 0;
+ else
+ held_addr <= iwb_adr_i;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ ack_d1 <= 1'b0;
+ else
+ ack_d1 <= iwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ miss_d1 <= 0;
+ else
+ miss_d1 <= cache_miss;
+
+//`define IC_NOCACHE
+//`define IC_BASIC
+//`define IC_FORWARDING_DP
+`define IC_FORWARDING_SP
+//`define IC_PREFETCH
+
+`ifdef IC_NOCACHE
+ assign iwb_dat_o = iram_dat_i;
+ assign iwb_ack_o = iwb_stb_i & (stb_d1 & ~ack_d1);
+ assign iram_adr_o = iwb_adr_i;
+ assign iram_en_o = 1'b1;
+ assign rd_line = 0;
+ assign wr_line = 0;
+ assign wr_tags = 0;
+ assign store_in_cache = 0;
+`endif
+
+`ifdef IC_BASIC // Very basic, no forwarding, 2 wait states on miss
+ assign iwb_dat_o = data_out;
+ assign iwb_ack_o = iwb_stb_i & cache_hit;
+ assign iram_adr_o = iwb_adr_i;
+ assign iram_en_o = 1'b1;
+ assign rd_line = iwb_adr_i[CWIDTH+1:2];
+ assign wr_line = rd_line;
+ assign wr_tags = iwb_adr_i[AWIDTH-1:CWIDTH+2];
+ assign store_in_cache = stb_d1 & miss_d1;
+`endif
+
+`ifdef IC_FORWARDING_DP // Simple forwarding, 1 wait state on miss, dual-port ram
+ assign iwb_dat_o = cache_hit ? data_out : iram_dat_i;
+ assign iwb_ack_o = iwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1));
+ assign iram_adr_o = iwb_adr_i;
+ assign iram_en_o = 1'b1;
+ assign rd_line = iwb_adr_i[CWIDTH+1:2];
+ assign wr_line = held_addr[CWIDTH+1:2];
+ assign wr_tags = held_addr[AWIDTH-1:CWIDTH+2];
+ assign store_in_cache = iwb_stb_i & stb_d1 & miss_d1 & ~ack_d1;
+`endif
+
+`ifdef IC_FORWARDING_SP // Simple forwarding, 1 wait state on miss, single-port ram
+ assign iwb_dat_o = cache_hit ? data_out : iram_dat_i;
+ assign iwb_ack_o = iwb_stb_i & (cache_hit | (stb_d1 & ~ack_d1));
+ assign iram_adr_o = iwb_adr_i;
+ assign iram_en_o = 1'b1;
+ assign rd_line = iwb_adr_i[CWIDTH+1:2];
+ assign wr_line = rd_line;
+ assign wr_tags = iwb_adr_i[AWIDTH-1:CWIDTH+2];
+ assign store_in_cache = iwb_stb_i & stb_d1 & miss_d1 & ~ack_d1;
+`endif
+
+`ifdef IC_PREFETCH // Forwarding plus prefetch
+
+`endif
+
+
+endmodule // icache
diff --git a/fpga/usrp2/control_lib/longfifo.v b/fpga/usrp2/control_lib/longfifo.v
new file mode 100644
index 000000000..c77f2dcb1
--- /dev/null
+++ b/fpga/usrp2/control_lib/longfifo.v
@@ -0,0 +1,167 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// FIFO intended to be interchangeable with shortfifo, but
+// based on block ram instead of SRL16's
+// only one clock domain
+
+// Port A is write port, Port B is read port
+
+module longfifo
+ #(parameter WIDTH=32, SIZE=9)
+ (input clk, input rst,
+ input [WIDTH-1:0] datain,
+ output [WIDTH-1:0] dataout,
+ input read,
+ input write,
+ input clear,
+ output full,
+ output empty,
+ output reg [15:0] space,
+ output reg [15:0] occupied);
+
+ // Read side states
+ localparam EMPTY = 0;
+ localparam PRE_READ = 1;
+ localparam READING = 2;
+
+ reg [SIZE-1:0] wr_addr, rd_addr;
+ reg [1:0] read_state;
+
+ reg empty_reg, full_reg;
+ always @(posedge clk)
+ if(rst)
+ wr_addr <= 0;
+ else if(clear)
+ wr_addr <= 0;
+ else if(write)
+ wr_addr <= wr_addr + 1;
+
+ ram_2port #(.DWIDTH(WIDTH),.AWIDTH(SIZE))
+ ram (.clka(clk),
+ .ena(1'b1),
+ .wea(write),
+ .addra(wr_addr),
+ .dia(datain),
+ .doa(),
+
+ .clkb(clk),
+ .enb((read_state==PRE_READ)|read),
+ .web(0),
+ .addrb(rd_addr),
+ .dib(0),
+ .dob(dataout));
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ read_state <= EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ if(clear)
+ begin
+ read_state <= EMPTY;
+ rd_addr <= 0;
+ empty_reg <= 1;
+ end
+ else
+ case(read_state)
+ EMPTY :
+ if(write)
+ begin
+ //rd_addr <= wr_addr;
+ read_state <= PRE_READ;
+ end
+ PRE_READ :
+ begin
+ read_state <= READING;
+ empty_reg <= 0;
+ rd_addr <= rd_addr + 1;
+ end
+
+ READING :
+ if(read)
+ if(rd_addr == wr_addr)
+ begin
+ empty_reg <= 1;
+ if(write)
+ read_state <= PRE_READ;
+ else
+ read_state <= EMPTY;
+ end
+ else
+ rd_addr <= rd_addr + 1;
+ endcase // case(read_state)
+
+ wire [SIZE-1:0] dont_write_past_me = rd_addr - 3;
+ wire becoming_full = wr_addr == dont_write_past_me;
+
+ always @(posedge clk)
+ if(rst)
+ full_reg <= 0;
+ else if(clear)
+ full_reg <= 0;
+ else if(read & ~write)
+ full_reg <= 0;
+ //else if(write & ~read & (wr_addr == (rd_addr-3)))
+ else if(write & ~read & becoming_full)
+ full_reg <= 1;
+
+ //assign empty = (read_state != READING);
+ assign empty = empty_reg;
+
+ // assign full = ((rd_addr - 1) == wr_addr);
+ assign full = full_reg;
+
+ //////////////////////////////////////////////
+ // space and occupied are for diagnostics only
+ // not guaranteed exact
+
+ localparam NUMLINES = (1<<SIZE)-2;
+ always @(posedge clk)
+ if(rst)
+ space <= NUMLINES;
+ else if(clear)
+ space <= NUMLINES;
+ else if(read & ~write)
+ space <= space + 1;
+ else if(write & ~read)
+ space <= space - 1;
+
+ always @(posedge clk)
+ if(rst)
+ occupied <= 0;
+ else if(clear)
+ occupied <= 0;
+ else if(read & ~write)
+ occupied <= occupied - 1;
+ else if(write & ~read)
+ occupied <= occupied + 1;
+
+ /*
+ wire [SIZE-1:0] fullness = wr_addr - rd_addr; // Approximate, for simulation only
+ assign occupied = {{16-SIZE{1'b0}},fullness};
+
+ wire [SIZE-1:0] free_space = rd_addr - wr_addr - 2; // Approximate, for SERDES flow control
+ assign space = {{16-SIZE{1'b0}},free_space};
+ */
+
+
+endmodule // longfifo
diff --git a/fpga/usrp2/control_lib/medfifo.v b/fpga/usrp2/control_lib/medfifo.v
new file mode 100644
index 000000000..0f66f6597
--- /dev/null
+++ b/fpga/usrp2/control_lib/medfifo.v
@@ -0,0 +1,66 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module medfifo
+ #(parameter WIDTH=32,
+ parameter DEPTH=1)
+ (input clk, input rst,
+ input [WIDTH-1:0] datain,
+ output [WIDTH-1:0] dataout,
+ input read,
+ input write,
+ input clear,
+ output full,
+ output empty,
+ output [7:0] space,
+ output [7:0] occupied);
+
+ localparam NUM_FIFOS = (1<<DEPTH);
+
+ wire [WIDTH-1:0] dout [0:NUM_FIFOS-1];
+ wire [0:NUM_FIFOS-1] full_x;
+ wire [0:NUM_FIFOS-1] empty_x;
+
+ shortfifo #(.WIDTH(WIDTH))
+ head (.clk(clk),.rst(rst),
+ .datain(datain),.write(write),.full(full),
+ .dataout(dout[0]),.read(~empty_x[0] & ~full_x[1]),.empty(empty_x[0]),
+ .clear(clear),.space(space[4:0]),.occupied() );
+
+ shortfifo #(.WIDTH(WIDTH))
+ tail (.clk(clk),.rst(rst),
+ .datain(dout[NUM_FIFOS-2]),.write(~empty_x[NUM_FIFOS-2] & ~full_x[NUM_FIFOS-1]),.full(full_x[NUM_FIFOS-1]),
+ .dataout(dataout),.read(read),.empty(empty),
+ .clear(clear),.space(),.occupied(occupied[4:0]) );
+
+ genvar i;
+ generate
+ for(i = 1; i < NUM_FIFOS-1 ; i = i + 1)
+ begin : gen_depth
+ shortfifo #(.WIDTH(WIDTH))
+ shortfifo (.clk(clk),.rst(rst),
+ .datain(dout[i-1]),.write(~full_x[i] & ~empty_x[i-1]),.full(full_x[i]),
+ .dataout(dout[i]),.read(~full_x[i+1] & ~empty_x[i]),.empty(empty_x[i]),
+ .clear(clear),.space(),.occupied() );
+ end
+ endgenerate
+
+ assign space[7:5] = 0;
+ assign occupied[7:5] = 0;
+
+endmodule // medfifo
diff --git a/fpga/usrp2/control_lib/mux4.v b/fpga/usrp2/control_lib/mux4.v
new file mode 100644
index 000000000..b1878f011
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux4.v
@@ -0,0 +1,33 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module mux4
+ #(parameter WIDTH=32, parameter DISABLED=0)
+ (input en,
+ input [1:0] sel,
+ input [WIDTH-1:0] i0,
+ input [WIDTH-1:0] i1,
+ input [WIDTH-1:0] i2,
+ input [WIDTH-1:0] i3,
+ output [WIDTH-1:0] o);
+
+ assign o = en ? (sel[1] ? (sel[0] ? i3 : i2) : (sel[0] ? i1 : i0)) :
+ DISABLED;
+
+endmodule // mux4
diff --git a/fpga/usrp2/control_lib/mux8.v b/fpga/usrp2/control_lib/mux8.v
new file mode 100644
index 000000000..bdb015dc3
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux8.v
@@ -0,0 +1,38 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module mux8
+ #(parameter WIDTH=32, parameter DISABLED=0)
+ (input en,
+ input [2:0] sel,
+ input [WIDTH-1:0] i0,
+ input [WIDTH-1:0] i1,
+ input [WIDTH-1:0] i2,
+ input [WIDTH-1:0] i3,
+ input [WIDTH-1:0] i4,
+ input [WIDTH-1:0] i5,
+ input [WIDTH-1:0] i6,
+ input [WIDTH-1:0] i7,
+ output [WIDTH-1:0] o);
+
+ assign o = en ? (sel[2] ? (sel[1] ? (sel[0] ? i7 : i6) : (sel[0] ? i5 : i4)) :
+ (sel[1] ? (sel[0] ? i3 : i2) : (sel[0] ? i1 : i0))) :
+ DISABLED;
+
+endmodule // mux8
diff --git a/fpga/usrp2/control_lib/mux_32_4.v b/fpga/usrp2/control_lib/mux_32_4.v
new file mode 100644
index 000000000..4a1244933
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux_32_4.v
@@ -0,0 +1,30 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module mux_32_4
+ (input [1:0] sel,
+ input [31:0] in0,
+ input [31:0] in1,
+ input [31:0] in2,
+ input [31:0] in3,
+ output [31:0] out);
+
+ assign out = sel[1] ? (sel[0] ? in3 : in2) : (sel[0] ? in1 : in0);
+
+endmodule // mux_32_4
diff --git a/fpga/usrp2/control_lib/nsgpio.v b/fpga/usrp2/control_lib/nsgpio.v
new file mode 100644
index 000000000..6c6873fee
--- /dev/null
+++ b/fpga/usrp2/control_lib/nsgpio.v
@@ -0,0 +1,93 @@
+// Modified from code originally by Richard Herveille, his copyright is below
+
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// OpenCores Simple General Purpose IO core ////
+//// ////
+//// Author: Richard Herveille ////
+//// richard@asics.ws ////
+//// www.asics.ws ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2002 Richard Herveille ////
+//// richard@asics.ws ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+//// ////
+//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
+//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
+//// POSSIBILITY OF SUCH DAMAGE. ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+
+
+module nsgpio
+ (input clk_i, input rst_i,
+ input cyc_i, input stb_i, input [4:0] adr_i, input we_i, input [31:0] dat_i,
+ output reg [31:0] dat_o, output reg ack_o,
+ input tx, input rx, inout [31:0] gpio
+ );
+
+ integer n;
+ reg [31:0] ddr;
+ reg [31:0] idle_out, rx_out, tx_out, fdx_out;
+ reg [31:0] rgpio, igpio;
+
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ always @(posedge clk_i or posedge rst_i)
+ if (rst_i)
+ ddr <= 0;
+ else if (wb_wr)
+ case( adr_i[4:2] )
+ 3'b000 :
+ idle_out <= dat_i;
+ 3'b001 :
+ rx_out <= dat_i;
+ 3'b010 :
+ tx_out <= dat_i;
+ 3'b011 :
+ fdx_out <= dat_i;
+ 3'b100 :
+ ddr <= dat_i;
+ endcase // case ( adr_i[4:2] )
+
+ always @(posedge clk_i)
+ dat_o <= gpio;
+
+ always @(posedge clk_i or posedge rst_i)
+ if (rst_i)
+ ack_o <= 1'b0;
+ else
+ ack_o <= wb_acc & !ack_o;
+
+ always @(posedge clk_i)
+ case({tx,rx})
+ 2'b00 : rgpio <= idle_out;
+ 2'b01 : rgpio <= rx_out;
+ 2'b10 : rgpio <= tx_out;
+ 2'b11 : rgpio <= fdx_out;
+ endcase // case ({tx,rx})
+
+ always @*
+ for(n=0;n<32;n=n+1)
+ igpio[n] <= ddr[n] ? rgpio[n] : 1'bz;
+
+ assign gpio = igpio;
+
+endmodule
diff --git a/fpga/usrp2/control_lib/nsgpio16LE.v b/fpga/usrp2/control_lib/nsgpio16LE.v
new file mode 100644
index 000000000..8aef0c7ae
--- /dev/null
+++ b/fpga/usrp2/control_lib/nsgpio16LE.v
@@ -0,0 +1,123 @@
+// Modified from code originally by Richard Herveille, his copyright is below
+
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// OpenCores Simple General Purpose IO core ////
+//// ////
+//// Author: Richard Herveille ////
+//// richard@asics.ws ////
+//// www.asics.ws ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2002 Richard Herveille ////
+//// richard@asics.ws ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+//// ////
+//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
+//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
+//// POSSIBILITY OF SUCH DAMAGE. ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+
+
+module nsgpio16LE
+ (input clk_i, input rst_i,
+ input cyc_i, input stb_i, input [3:0] adr_i, input we_i, input [15:0] dat_i,
+ output reg [15:0] dat_o, output reg ack_o,
+ input [31:0] atr, input [31:0] debug_0, input [31:0] debug_1,
+ inout [31:0] gpio
+ );
+
+ reg [31:0] ctrl, line, ddr, dbg, lgpio;
+
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ always @(posedge clk_i or posedge rst_i)
+ if (rst_i)
+ begin
+ ctrl <= 32'h0;
+ line <= 32'h0;
+ ddr <= 32'h0;
+ dbg <= 32'h0;
+ end
+ else if (wb_wr)
+ case( adr_i[3:1] )
+ 3'b000 :
+ line[15:0] <= dat_i;
+ 3'b001 :
+ line[31:16] <= dat_i;
+ 3'b010 :
+ ddr[15:0] <= dat_i;
+ 3'b011 :
+ ddr[31:16] <= dat_i;
+ 3'b100 :
+ ctrl[15:0] <= dat_i;
+ 3'b101 :
+ ctrl[31:16] <= dat_i;
+ 3'b110 :
+ dbg[15:0] <= dat_i;
+ 3'b111 :
+ dbg[31:16] <= dat_i;
+ endcase // case ( adr_i[3:1] )
+
+ always @(posedge clk_i)
+ case (adr_i[3:1])
+ 3'b000 :
+ dat_o <= lgpio[15:0];
+ 3'b001 :
+ dat_o <= lgpio[31:16];
+ 3'b010 :
+ dat_o <= ddr[15:0];
+ 3'b011 :
+ dat_o <= ddr[31:16];
+ 3'b100 :
+ dat_o <= ctrl[15:0];
+ 3'b101 :
+ dat_o <= ctrl[31:16];
+ 3'b110 :
+ dat_o <= dbg[15:0];
+ 3'b111 :
+ dat_o <= dbg[31:16];
+ endcase // case (adr_i[3:1])
+
+
+ always @(posedge clk_i or posedge rst_i)
+ if (rst_i)
+ ack_o <= 1'b0;
+ else
+ ack_o <= wb_acc & !ack_o;
+
+ // latch GPIO input pins
+ always @(posedge clk_i)
+ lgpio <= gpio;
+
+ // assign GPIO outputs
+ integer n;
+ reg [31:0] igpio; // temporary internal signal
+
+ always @(ctrl or line or debug_1 or debug_0 or atr or ddr or dbg)
+ for(n=0;n<32;n=n+1)
+ igpio[n] <= ddr[n] ? (dbg[n] ? (ctrl[n] ? debug_1[n] : debug_0[n]) :
+ (ctrl[n] ? atr[n] : line[n]) )
+ : 1'bz;
+
+ assign gpio = igpio;
+
+endmodule
+
diff --git a/fpga/usrp2/control_lib/oneshot_2clk.v b/fpga/usrp2/control_lib/oneshot_2clk.v
new file mode 100644
index 000000000..7ed5bc8f6
--- /dev/null
+++ b/fpga/usrp2/control_lib/oneshot_2clk.v
@@ -0,0 +1,52 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Retime a single bit from one clock domain to another
+// Guarantees that no matter what the relative clock rates, if the in signal is high for at least
+// one clock cycle in the clk_in domain, then the out signal will be high for at least one
+// clock cycle in the clk_out domain. If the in signal goes high again before the process is done
+// the behavior is undefined. No other guarantees. Designed for passing reset into a new
+// clock domain.
+
+module oneshot_2clk
+ (input clk_in,
+ input in,
+ input clk_out,
+ output reg out);
+
+ reg del_in = 0;
+ reg sendit = 0, gotit = 0;
+ reg sendit_d = 0, gotit_d = 0;
+
+ always @(posedge clk_in) del_in <= in;
+
+ always @(posedge clk_in)
+ if(in & ~del_in) // we have a positive edge
+ sendit <= 1;
+ else if(gotit)
+ sendit <= 0;
+
+ always @(posedge clk_out) sendit_d <= sendit;
+ always @(posedge clk_out) out <= sendit_d;
+
+ always @(posedge clk_in) gotit_d <= out;
+ always @(posedge clk_in) gotit <= gotit_d;
+
+endmodule // oneshot_2clk
+
+
diff --git a/fpga/usrp2/control_lib/pic.v b/fpga/usrp2/control_lib/pic.v
new file mode 100644
index 000000000..9b9944d4a
--- /dev/null
+++ b/fpga/usrp2/control_lib/pic.v
@@ -0,0 +1,183 @@
+
+// Heavily modified by M. Ettus, 2009, little original code remains
+// Modified by M. Ettus, 2008 for 32 bit width
+
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// OpenCores Simple Programmable Interrupt Controller ////
+//// ////
+//// Author: Richard Herveille ////
+//// richard@asics.ws ////
+//// www.asics.ws ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2002 Richard Herveille ////
+//// richard@asics.ws ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer.////
+//// ////
+//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY ////
+//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED ////
+//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ////
+//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR ////
+//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, ////
+//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ////
+//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ////
+//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR ////
+//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF ////
+//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ////
+//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ////
+//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ////
+//// POSSIBILITY OF SUCH DAMAGE. ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//
+// This is a simple Programmable Interrupt Controller.
+// The number of interrupts is depending on the databus size.
+// There's one interrupt input per databit (i.e. 16 interrupts for a 16
+// bit databus).
+// All attached devices share the same CPU priority level.
+//
+//
+//
+// Registers:
+//
+// 0x00: EdgeEnable Register
+// bits 7:0 R/W Edge Enable '1' = edge triggered interrupt source
+// '0' = level triggered interrupt source
+// 0x01: PolarityRegister
+// bits 7:0 R/W Polarity '1' = high level / rising edge
+// '0' = low level / falling edge
+// 0x02: MaskRegister
+// bits 7:0 R/W Mask '1' = interrupt masked (disabled)
+// '0' = interrupt not masked (enabled)
+// 0x03: PendingRegister
+// bits 7:0 R/W Pending '1' = interrupt pending
+// '0' = no interrupt pending
+//
+// A CPU interrupt is generated when an interrupt is pending and its
+// MASK bit is cleared.
+//
+//
+//
+// HOWTO:
+//
+// Clearing pending interrupts:
+// Writing a '1' to a bit in the interrupt pending register clears the
+// interrupt. Make sure to clear the interrupt at the source before
+// writing to the interrupt pending register. Otherwise the interrupt
+// will be set again.
+//
+// Priority based interrupts:
+// Upon reception of an interrupt, check the interrupt register and
+// determine the highest priority interrupt. Mask all interrupts from the
+// current level to the lowest level. This negates the interrupt line, and
+// makes sure only interrupts with a higher level are triggered. After
+// completion of the interrupt service routine, clear the interrupt source,
+// the interrupt bit in the pending register, and restore the MASK register
+// to it's previous state.
+//
+// Addapt the core for fewer interrupt sources:
+// If less than 8 interrupt sources are required, than the 'is' parameter
+// can be set to the amount of required interrupts. Interrupts are mapped
+// starting at the LSBs. So only the 'is' LSBs per register are valid. All
+// other bits (i.e. the 8-'is' MSBs) are set to zero '0'.
+// Codesize is approximately linear to the amount of interrupts. I.e. using
+// 4 instead of 8 interrupt sources reduces the size by approx. half.
+//
+
+
+module pic
+ (input clk_i, input rst_i, input cyc_i, input stb_i,
+ input [2:0] adr_i,
+ input we_i,
+ input [31:0] dat_i,
+ output reg [31:0] dat_o,
+ output reg ack_o,
+ output reg int_o,
+ input [31:0] irq
+ );
+
+ reg [31:0] pol, edgen, pending, mask; // register bank
+ reg [31:0] lirq, dirq; // latched irqs, delayed latched irqs
+
+ // latch interrupt inputs
+ always @(posedge clk_i)
+ lirq <= irq;
+
+ // generate delayed latched irqs
+ always @(posedge clk_i)
+ dirq <= lirq;
+
+ // generate actual triggers
+ function trigger;
+ input edgen, pol, lirq, dirq;
+ reg edge_irq, level_irq;
+ begin
+ edge_irq = pol ? (lirq & ~dirq) : (dirq & ~lirq);
+ level_irq = pol ? lirq : ~lirq;
+ trigger = edgen ? edge_irq : level_irq;
+ end
+ endfunction
+
+ reg [31:0] irq_event;
+ integer n;
+ always @(posedge clk_i)
+ for(n = 0; n < 32; n = n+1)
+ irq_event[n] <= trigger(edgen[n], pol[n], lirq[n], dirq[n]);
+
+ // generate wishbone register bank writes
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ always @(posedge clk_i)
+ if (rst_i)
+ begin
+ pol <= 0; // clear polarity register
+ edgen <= 0; // clear edge enable register
+ mask <= 0; // mask all interrupts
+ end
+ else if(wb_wr) // wishbone write cycle??
+ case (adr_i) // synopsys full_case parallel_case
+ 3'd0 : edgen <= dat_i; // EDGE-ENABLE register
+ 3'd1 : pol <= dat_i; // POLARITY register
+ 3'd2 : mask <= dat_i; // MASK register
+ 3'd3 : ; // PENDING register is a special case (see below)
+ 3'd4 : ; // Priority encoded live (pending & ~mask)
+ endcase
+
+ // pending register is a special case
+ always @(posedge clk_i)
+ if (rst_i)
+ pending <= 0; // clear all pending interrupts
+ else if ( wb_wr & (adr_i == 3'd3) )
+ pending <= (pending & ~dat_i) | irq_event;
+ else
+ pending <= pending | irq_event;
+
+ wire [31:0] live_enc;
+ priority_enc priority_enc ( .in(pending & ~mask), .out(live_enc) );
+
+ always @(posedge clk_i)
+ case (adr_i) // synopsys full_case parallel_case
+ 3'd0 : dat_o <= edgen;
+ 3'd1 : dat_o <= pol;
+ 3'd2 : dat_o <= mask;
+ 3'd3 : dat_o <= pending;
+ 3'd4 : dat_o <= live_enc;
+ endcase
+
+ always @(posedge clk_i)
+ ack_o <= wb_acc & !ack_o;
+
+ always @(posedge clk_i)
+ if(rst_i)
+ int_o <= 0;
+ else
+ int_o <= |(pending & ~mask);
+
+endmodule
diff --git a/fpga/usrp2/control_lib/priority_enc.v b/fpga/usrp2/control_lib/priority_enc.v
new file mode 100644
index 000000000..d30870be9
--- /dev/null
+++ b/fpga/usrp2/control_lib/priority_enc.v
@@ -0,0 +1,61 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module priority_enc
+ (input [31:0] in,
+ output reg [31:0] out);
+
+ always @*
+ casex(in)
+ 32'b1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 31;
+ 32'b01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 30;
+ 32'b001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 29;
+ 32'b0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 28;
+ 32'b0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 27;
+ 32'b0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 26;
+ 32'b0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 25;
+ 32'b0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 24;
+ 32'b0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 23;
+ 32'b0000_0000_01xx_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 22;
+ 32'b0000_0000_001x_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 21;
+ 32'b0000_0000_0001_xxxx_xxxx_xxxx_xxxx_xxxx : out <= 20;
+ 32'b0000_0000_0000_1xxx_xxxx_xxxx_xxxx_xxxx : out <= 19;
+ 32'b0000_0000_0000_01xx_xxxx_xxxx_xxxx_xxxx : out <= 18;
+ 32'b0000_0000_0000_001x_xxxx_xxxx_xxxx_xxxx : out <= 17;
+ 32'b0000_0000_0000_0001_xxxx_xxxx_xxxx_xxxx : out <= 16;
+ 32'b0000_0000_0000_0000_1xxx_xxxx_xxxx_xxxx : out <= 15;
+ 32'b0000_0000_0000_0000_01xx_xxxx_xxxx_xxxx : out <= 14;
+ 32'b0000_0000_0000_0000_001x_xxxx_xxxx_xxxx : out <= 13;
+ 32'b0000_0000_0000_0000_0001_xxxx_xxxx_xxxx : out <= 12;
+ 32'b0000_0000_0000_0000_0000_1xxx_xxxx_xxxx : out <= 11;
+ 32'b0000_0000_0000_0000_0000_01xx_xxxx_xxxx : out <= 10;
+ 32'b0000_0000_0000_0000_0000_001x_xxxx_xxxx : out <= 9;
+ 32'b0000_0000_0000_0000_0000_0001_xxxx_xxxx : out <= 8;
+ 32'b0000_0000_0000_0000_0000_0000_1xxx_xxxx : out <= 7;
+ 32'b0000_0000_0000_0000_0000_0000_01xx_xxxx : out <= 6;
+ 32'b0000_0000_0000_0000_0000_0000_001x_xxxx : out <= 5;
+ 32'b0000_0000_0000_0000_0000_0000_0001_xxxx : out <= 4;
+ 32'b0000_0000_0000_0000_0000_0000_0000_1xxx : out <= 3;
+ 32'b0000_0000_0000_0000_0000_0000_0000_01xx : out <= 2;
+ 32'b0000_0000_0000_0000_0000_0000_0000_001x : out <= 1;
+ 32'b0000_0000_0000_0000_0000_0000_0000_0001 : out <= 0;
+ 32'b0000_0000_0000_0000_0000_0000_0000_0000 : out <= 32'hFFFF_FFFF;
+ default : out <= 32'hFFFF_FFFF;
+ endcase // casex (in)
+
+endmodule // priority_enc
diff --git a/fpga/usrp2/control_lib/quad_uart.v b/fpga/usrp2/control_lib/quad_uart.v
new file mode 100644
index 000000000..39998150d
--- /dev/null
+++ b/fpga/usrp2/control_lib/quad_uart.v
@@ -0,0 +1,88 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module quad_uart
+ #(parameter TXDEPTH = 1,
+ parameter RXDEPTH = 1)
+ (input clk_i, input rst_i,
+ input we_i, input stb_i, input cyc_i, output reg ack_o,
+ input [4:0] adr_i, input [31:0] dat_i, output reg [31:0] dat_o,
+ output [3:0] rx_int_o, output [3:0] tx_int_o,
+ output [3:0] tx_o, input [3:0] rx_i, output [3:0] baud_o
+ );
+
+ // Register Map
+ localparam SUART_CLKDIV = 0;
+ localparam SUART_TXLEVEL = 1;
+ localparam SUART_RXLEVEL = 2;
+ localparam SUART_TXCHAR = 3;
+ localparam SUART_RXCHAR = 4;
+
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ reg [15:0] clkdiv[0:3];
+ wire [7:0] rx_char[0:3];
+ wire [3:0] tx_fifo_full, rx_fifo_empty;
+ wire [7:0] tx_fifo_level[0:3], rx_fifo_level[0:3];
+
+ always @(posedge clk_i)
+ if (rst_i)
+ ack_o <= 1'b0;
+ else
+ ack_o <= wb_acc & ~ack_o;
+
+ integer i;
+ always @(posedge clk_i)
+ if (rst_i)
+ for(i=0;i<4;i=i+1)
+ clkdiv[i] <= 0;
+ else if (wb_wr)
+ case(adr_i[2:0])
+ SUART_CLKDIV : clkdiv[adr_i[4:3]] <= dat_i[15:0];
+ endcase // case(adr_i)
+
+ always @(posedge clk_i)
+ case (adr_i[2:0])
+ SUART_TXLEVEL : dat_o <= tx_fifo_level[adr_i[4:3]];
+ SUART_RXLEVEL : dat_o <= rx_fifo_level[adr_i[4:3]];
+ SUART_RXCHAR : dat_o <= rx_char[adr_i[4:3]];
+ endcase // case(adr_i)
+
+ genvar j;
+ generate
+ for(j=0;j<4;j=j+1)
+ begin : gen_uarts
+ simple_uart_tx #(.DEPTH(TXDEPTH)) simple_uart_tx
+ (.clk(clk_i),.rst(rst_i),
+ .fifo_in(dat_i[7:0]),.fifo_write(ack_o && wb_wr && (adr_i[2:0] == SUART_TXCHAR) && (adr_i[4:3]==j)),
+ .fifo_level(tx_fifo_level[j]),.fifo_full(tx_fifo_full[j]),
+ .clkdiv(clkdiv[j]),.baudclk(baud_o[j]),.tx(tx_o[j]));
+
+ simple_uart_rx #(.DEPTH(RXDEPTH)) simple_uart_rx
+ (.clk(clk_i),.rst(rst_i),
+ .fifo_out(rx_char[j]),.fifo_read(ack_o && ~wb_wr && (adr_i[2:0] == SUART_RXCHAR) && (adr_i[4:3]==j)),
+ .fifo_level(rx_fifo_level[j]),.fifo_empty(rx_fifo_empty[j]),
+ .clkdiv(clkdiv[j]),.rx(rx_i[j]));
+ end // block: gen_uarts
+ endgenerate
+
+ assign tx_int_o = ~tx_fifo_full; // Interrupt for those that have space
+ assign rx_int_o = ~rx_fifo_empty; // Interrupt for those that have data
+
+endmodule // quad_uart
diff --git a/fpga/usrp2/control_lib/ram_2port.v b/fpga/usrp2/control_lib/ram_2port.v
new file mode 100644
index 000000000..86d7e4703
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_2port.v
@@ -0,0 +1,59 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module ram_2port
+ #(parameter DWIDTH=32,
+ parameter AWIDTH=9)
+ (input clka,
+ input ena,
+ input wea,
+ input [AWIDTH-1:0] addra,
+ input [DWIDTH-1:0] dia,
+ output reg [DWIDTH-1:0] doa,
+
+ input clkb,
+ input enb,
+ input web,
+ input [AWIDTH-1:0] addrb,
+ input [DWIDTH-1:0] dib,
+ output reg [DWIDTH-1:0] dob);
+
+ reg [DWIDTH-1:0] ram [(1<<AWIDTH)-1:0];
+ integer i;
+ initial
+ for(i=0;i<(1<<AWIDTH);i=i+1)
+ ram[i] <= {DWIDTH{1'b0}};
+
+ always @(posedge clka) begin
+ if (ena)
+ begin
+ if (wea)
+ ram[addra] <= dia;
+ doa <= ram[addra];
+ end
+ end
+ always @(posedge clkb) begin
+ if (enb)
+ begin
+ if (web)
+ ram[addrb] <= dib;
+ dob <= ram[addrb];
+ end
+ end
+endmodule // ram_2port
diff --git a/fpga/usrp2/control_lib/ram_2port_mixed_width.v b/fpga/usrp2/control_lib/ram_2port_mixed_width.v
new file mode 100644
index 000000000..2910d4041
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_2port_mixed_width.v
@@ -0,0 +1,137 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module ram_2port_mixed_width
+ (input clk16,
+ input en16,
+ input we16,
+ input [10:0] addr16,
+ input [15:0] di16,
+ output [15:0] do16,
+ input clk32,
+ input en32,
+ input we32,
+ input [9:0] addr32,
+ input [31:0] di32,
+ output [31:0] do32);
+
+ wire en32a = en32 & ~addr32[9];
+ wire en32b = en32 & addr32[9];
+ wire en16a = en16 & ~addr16[10];
+ wire en16b = en16 & addr16[10];
+
+ wire [31:0] do32a, do32b;
+ wire [15:0] do16a, do16b;
+
+ assign do32 = addr32[9] ? do32b : do32a;
+ assign do16 = addr16[10] ? do16b : do16a;
+
+ RAMB16BWE_S36_S18 #(.INIT_A(36'h000000000),
+ .INIT_B(18'h00000),
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(18'h00000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST") // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ )
+ RAMB16BWE_S36_S18_0 (.DOA(do32a), // Port A 32-bit Data Output
+ .DOB(do16a), // Port B 16-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .DOPB(), // Port B 2-bit Parity Output
+ .ADDRA(addr32[8:0]), // Port A 9-bit Address Input
+ .ADDRB(addr16[9:0]), // Port B 10-bit Address Input
+ .CLKA(clk32), // Port A 1-bit Clock
+ .CLKB(clk16), // Port B 1-bit Clock
+ .DIA(di32), // Port A 32-bit Data Input
+ .DIB(di16), // Port B 16-bit Data Input
+ .DIPA(0), // Port A 4-bit parity Input
+ .DIPB(0), // Port-B 2-bit parity Input
+ .ENA(en32a), // Port A 1-bit RAM Enable Input
+ .ENB(en16a), // Port B 1-bit RAM Enable Input
+ .SSRA(0), // Port A 1-bit Synchronous Set/Reset Input
+ .SSRB(0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEA({4{we32}}), // Port A 4-bit Write Enable Input
+ .WEB({2{we16}}) // Port B 2-bit Write Enable Input
+ );
+
+ RAMB16BWE_S36_S18 #(.INIT_A(36'h000000000),
+ .INIT_B(18'h00000),
+ .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL"
+ .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion
+ .SRVAL_B(18'h00000), // Port B output value upon SSR assertion
+ .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ .WRITE_MODE_B("WRITE_FIRST") // WRITE_FIRST, READ_FIRST or NO_CHANGE
+ )
+ RAMB16BWE_S36_S18_1 (.DOA(do32b), // Port A 32-bit Data Output
+ .DOB(do16b), // Port B 16-bit Data Output
+ .DOPA(), // Port A 4-bit Parity Output
+ .DOPB(), // Port B 2-bit Parity Output
+ .ADDRA(addr32[8:0]), // Port A 9-bit Address Input
+ .ADDRB(addr16[9:0]), // Port B 10-bit Address Input
+ .CLKA(clk32), // Port A 1-bit Clock
+ .CLKB(clk16), // Port B 1-bit Clock
+ .DIA(di32), // Port A 32-bit Data Input
+ .DIB(di16), // Port B 16-bit Data Input
+ .DIPA(0), // Port A 4-bit parity Input
+ .DIPB(0), // Port-B 2-bit parity Input
+ .ENA(en32b), // Port A 1-bit RAM Enable Input
+ .ENB(en16b), // Port B 1-bit RAM Enable Input
+ .SSRA(0), // Port A 1-bit Synchronous Set/Reset Input
+ .SSRB(0), // Port B 1-bit Synchronous Set/Reset Input
+ .WEA({4{we32}}), // Port A 4-bit Write Enable Input
+ .WEB({2{we16}}) // Port B 2-bit Write Enable Input
+ );
+
+endmodule // ram_2port_mixed_width
+
+
+
+
+// ISE 10.1.03 chokes on the following
+
+/*
+
+ reg [31:0] ram [(1<<AWIDTH)-1:0];
+ integer i;
+ initial
+ for(i=0;i<512;i=i+1)
+ ram[i] <= 32'b0;
+
+ always @(posedge clk16)
+ if (en16)
+ begin
+ if (we16)
+ if(addr16[0])
+ ram[addr16[10:1]][15:0] <= di16;
+ else
+ ram[addr16[10:1]][31:16] <= di16;
+ do16 <= addr16[0] ? ram[addr16[10:1]][15:0] : ram[addr16[10:1]][31:16];
+ end
+
+ always @(posedge clk32)
+ if (en32)
+ begin
+ if (we32)
+ ram[addr32] <= di32;
+ do32 <= ram[addr32];
+ end
+
+endmodule // ram_2port_mixed_width
+
+
+ */
diff --git a/fpga/usrp2/control_lib/ram_harv_cache.v b/fpga/usrp2/control_lib/ram_harv_cache.v
new file mode 100644
index 000000000..e68ed7f68
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harv_cache.v
@@ -0,0 +1,92 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Dual ported, Harvard architecture, cached ram
+
+module ram_harv_cache
+ #(parameter AWIDTH=15,parameter RAM_SIZE=16384,parameter ICWIDTH=6,parameter DCWIDTH=6)
+ (input wb_clk_i, input wb_rst_i,
+
+ input [AWIDTH-1:0] ram_loader_adr_i,
+ input [31:0] ram_loader_dat_i,
+ input ram_loader_stb_i,
+ input [3:0] ram_loader_sel_i,
+ input ram_loader_we_i,
+ output ram_loader_ack_o,
+ input ram_loader_done_i,
+
+ input [AWIDTH-1:0] iwb_adr_i,
+ input iwb_stb_i,
+ output [31:0] iwb_dat_o,
+ output iwb_ack_o,
+
+ input [AWIDTH-1:0] dwb_adr_i,
+ input [31:0] dwb_dat_i,
+ output [31:0] dwb_dat_o,
+ input dwb_we_i,
+ output dwb_ack_o,
+ input dwb_stb_i,
+ input [3:0] dwb_sel_i,
+
+ input flush_icache );
+
+ wire [31:0] iram_dat, dram_dat_i, dram_dat_o;
+ wire [AWIDTH-1:0] iram_adr, dram_adr;
+ wire iram_en, dram_en, dram_we;
+ wire [3:0] dram_sel;
+
+ dpram32 #(.AWIDTH(AWIDTH),.RAM_SIZE(RAM_SIZE)) sys_ram
+ (.clk(wb_clk_i),
+
+ .adr1_i(ram_loader_done_i ? iram_adr : ram_loader_adr_i),
+ .dat1_i(ram_loader_dat_i),
+ .dat1_o(iram_dat),
+ .we1_i(ram_loader_done_i ? 1'b0 : ram_loader_we_i),
+ .en1_i(ram_loader_done_i ? iram_en : ram_loader_stb_i),
+ .sel1_i(ram_loader_done_i ? 4'hF : ram_loader_sel_i),
+
+ .adr2_i(dram_adr),.dat2_i(dram_dat_i),.dat2_o(dram_dat_o),
+ .we2_i(dram_we),.en2_i(dram_en),.sel2_i(dram_sel) );
+
+ // Data bus side
+ dcache #(.AWIDTH(AWIDTH),.CWIDTH(DCWIDTH))
+ dcache(.wb_clk_i(wb_clk_i),.wb_rst_i(wb_rst_i),
+ .dwb_adr_i(dwb_adr_i),.dwb_stb_i(dwb_stb_i),
+ .dwb_we_i(dwb_we_i),.dwb_sel_i(dwb_sel_i),
+ .dwb_dat_i(dwb_dat_i),.dwb_dat_o(dwb_dat_o),
+ .dwb_ack_o(dwb_ack_o),
+ .dram_dat_i(dram_dat_o),.dram_dat_o(dram_dat_i),.dram_adr_o(dram_adr),
+ .dram_we_o(dram_we),.dram_en_o(dram_en), .dram_sel_o(dram_sel) );
+
+ // Instruction bus side
+ icache #(.AWIDTH(AWIDTH),.CWIDTH(ICWIDTH))
+ icache(.wb_clk_i(wb_clk_i),.wb_rst_i(wb_rst_i),
+ .iwb_adr_i(iwb_adr_i),.iwb_stb_i(iwb_stb_i),
+ .iwb_dat_o(iwb_dat_o),.iwb_ack_o(iwb_ack_o),
+ .iram_dat_i(iram_dat),.iram_adr_o(iram_adr),.iram_en_o(iram_en),
+ .flush(flush_icache));
+
+ // RAM loader
+ assign ram_loader_ack_o = ram_loader_stb_i;
+
+ // Performance Monitoring
+ wire i_wait = iwb_stb_i & ~iwb_ack_o;
+ wire d_wait = dwb_stb_i & ~dwb_ack_o;
+
+endmodule // ram_harv_cache
diff --git a/fpga/usrp2/control_lib/ram_harvard.v b/fpga/usrp2/control_lib/ram_harvard.v
new file mode 100644
index 000000000..00ffb1984
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harvard.v
@@ -0,0 +1,84 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Dual ported, Harvard architecture, cached ram
+
+module ram_harvard
+ #(parameter AWIDTH=15,
+ parameter RAM_SIZE=16384,
+ parameter ICWIDTH=6,
+ parameter DCWIDTH=6)
+
+ (input wb_clk_i,
+ input wb_rst_i,
+ // Firmware download port.
+ input [AWIDTH-1:0] ram_loader_adr_i,
+ input [31:0] ram_loader_dat_i,
+ input [3:0] ram_loader_sel_i,
+ input ram_loader_stb_i,
+ input ram_loader_we_i,
+ input ram_loader_done_i,
+ // Instruction fetch port.
+ input [AWIDTH-1:0] if_adr,
+ output [31:0] if_data,
+ // Data access port.
+ input [AWIDTH-1:0] dwb_adr_i,
+ input [31:0] dwb_dat_i,
+ output [31:0] dwb_dat_o,
+ input dwb_we_i,
+ output dwb_ack_o,
+ input dwb_stb_i,
+ input [3:0] dwb_sel_i );
+
+ reg ack_d1;
+ reg stb_d1;
+
+ dpram32 #(.AWIDTH(AWIDTH),.RAM_SIZE(RAM_SIZE))
+ sys_ram
+ (.clk(wb_clk_i),
+ .adr1_i(ram_loader_done_i ? if_adr : ram_loader_adr_i),
+ .dat1_i(ram_loader_dat_i),
+ .dat1_o(if_data),
+ .we1_i(ram_loader_done_i ? 1'b0 : ram_loader_we_i),
+ .en1_i(ram_loader_done_i ? 1'b1 : ram_loader_stb_i),
+ //.sel1_i(ram_loader_done_i ? 4'hF : ram_loader_sel_i),
+ .sel1_i(ram_loader_sel_i), // Sel is only for writes anyway
+ .adr2_i(dwb_adr_i),
+ .dat2_i(dwb_dat_i),
+ .dat2_o(dwb_dat_o),
+ .we2_i(dwb_we_i),
+ .en2_i(dwb_stb_i),
+ .sel2_i(dwb_sel_i)
+ );
+
+ assign dwb_ack_o = dwb_stb_i & (dwb_we_i | (stb_d1 & ~ack_d1));
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ ack_d1 <= 1'b0;
+ else
+ ack_d1 <= dwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ stb_d1 <= 0;
+ else
+ stb_d1 <= dwb_stb_i;
+
+endmodule // ram_harvard
diff --git a/fpga/usrp2/control_lib/ram_harvard2.v b/fpga/usrp2/control_lib/ram_harvard2.v
new file mode 100644
index 000000000..d8fe472f5
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harvard2.v
@@ -0,0 +1,94 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Dual ported, Harvard architecture
+
+module ram_harvard2
+ #(parameter AWIDTH=15,
+ parameter RAM_SIZE=32768)
+ (input wb_clk_i,
+ input wb_rst_i,
+ // Instruction fetch port.
+ input [AWIDTH-1:0] if_adr,
+ output reg [31:0] if_data,
+ // Data access port.
+ input [AWIDTH-1:0] dwb_adr_i,
+ input [31:0] dwb_dat_i,
+ output reg [31:0] dwb_dat_o,
+ input dwb_we_i,
+ output dwb_ack_o,
+ input dwb_stb_i,
+ input [3:0] dwb_sel_i);
+
+ reg ack_d1;
+ reg stb_d1;
+
+ assign dwb_ack_o = dwb_stb_i & (dwb_we_i | (stb_d1 & ~ack_d1));
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ ack_d1 <= 1'b0;
+ else
+ ack_d1 <= dwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ stb_d1 <= 0;
+ else
+ stb_d1 <= dwb_stb_i;
+
+ reg [7:0] ram0 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram1 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram2 [0:(RAM_SIZE/4)-1];
+ reg [7:0] ram3 [0:(RAM_SIZE/4)-1];
+
+ // Port 1, Read only
+ always @(posedge wb_clk_i)
+ if_data[31:24] <= ram3[if_adr[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if_data[23:16] <= ram2[if_adr[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if_data[15:8] <= ram1[if_adr[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if_data[7:0] <= ram0[if_adr[AWIDTH-1:2]];
+
+ // Port 2, R/W
+ always @(posedge wb_clk_i)
+ if(dwb_stb_i) dwb_dat_o[31:24] <= ram3[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if(dwb_stb_i) dwb_dat_o[23:16] <= ram2[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if(dwb_stb_i) dwb_dat_o[15:8] <= ram1[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ if(dwb_stb_i) dwb_dat_o[7:0] <= ram0[dwb_adr_i[AWIDTH-1:2]];
+
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[3])
+ ram3[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[31:24];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[2])
+ ram2[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[23:16];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[1])
+ ram1[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[15:8];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[0])
+ ram0[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[7:0];
+
+endmodule // ram_harvard
diff --git a/fpga/usrp2/control_lib/ram_loader.v b/fpga/usrp2/control_lib/ram_loader.v
new file mode 100644
index 000000000..85ccf91b4
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_loader.v
@@ -0,0 +1,278 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module ram_loader
+ #(parameter AWIDTH=16, RAM_SIZE=16384)
+ (
+ // Wishbone I/F and clock domain
+ input wb_clk,
+ input dsp_clk,
+ input ram_loader_rst,
+ output wire [31:0] wb_dat,
+ output wire [AWIDTH-1:0] wb_adr,
+ output wb_stb,
+ output reg [3:0] wb_sel,
+ output wb_we,
+ output reg ram_loader_done,
+ // CPLD signals and clock domain
+ input cpld_clk,
+ input cpld_din,
+ output reg cpld_start,
+ output reg cpld_mode,
+ output reg cpld_done,
+ input cpld_detached
+ );
+
+ localparam S0 = 0;
+ localparam S1 = 1;
+ localparam S2 = 2;
+ localparam S3 = 3;
+ localparam S4 = 4;
+ localparam S5 = 5;
+ localparam S6 = 6;
+ localparam RESET = 7;
+
+ localparam WB_IDLE = 0;
+ localparam WB_WRITE = 1;
+
+
+ reg [AWIDTH+2:0] count; // 3 LSB's count bits in, the MSB's generate the Wishbone address
+ reg [6:0] shift_reg;
+ reg [7:0] data_reg;
+ reg sampled_clk;
+ reg sampled_clk_meta;
+ reg sampled_din;
+ reg inc_count;
+ reg load_data_reg;
+ reg shift;
+ reg wb_state, wb_next_state;
+ reg [2:0] state, next_state;
+
+ //
+ // CPLD clock doesn't free run and is approximately 12.5MHz.
+ // Use 50MHz Wishbone clock to sample it as a signal and avoid having
+ // an extra clock domain for no reason.
+ //
+
+ always @(posedge dsp_clk or posedge ram_loader_rst)
+ if (ram_loader_rst)
+ begin
+ sampled_clk_meta <= 1'b0;
+ sampled_clk <= 1'b0;
+ sampled_din <= 1'b0;
+ count <= 'h7FFF8; // Initialize so that address will be 0 when first byte fully received.
+ data_reg <= 0;
+ shift_reg <= 0;
+ end
+ else
+ begin
+ sampled_clk_meta <= cpld_clk;
+ sampled_clk <= sampled_clk_meta;
+ sampled_din <= cpld_din;
+ if (inc_count)
+ count <= count + 1'b1;
+ if (load_data_reg)
+ data_reg <= {shift_reg,sampled_din};
+ if (shift)
+ shift_reg <= {shift_reg[5:0],sampled_din};
+ end // else: !if(ram_loader_rst)
+
+
+ always @(posedge dsp_clk or posedge ram_loader_rst)
+ if (ram_loader_rst)
+ state <= RESET;
+ else
+ state <= next_state;
+
+
+ always @*
+ begin
+ // Defaults
+ next_state = state;
+ cpld_start = 1'b0;
+ shift = 1'b0;
+ inc_count = 0;
+ load_data_reg = 1'b0;
+ ram_loader_done = 1'b0;
+ cpld_mode = 1'b0;
+ cpld_done = 1'b1;
+
+
+
+ case (state) //synthesis parallel_case full_case
+ // After reset wait until CPLD indicates its detached.
+ RESET: begin
+ if (cpld_detached)
+ next_state = S0;
+ else
+ next_state = RESET;
+ end
+
+ // Assert cpld_start to signal the CPLD its to start sending serial clock and data.
+ // Assume cpld_clk is low as we transition into search for first rising edge
+ S0: begin
+ cpld_start = 1'b1;
+ cpld_done = 1'b0;
+ if (~cpld_detached)
+ next_state = S2;
+ else
+ next_state = S0;
+ end
+
+ //
+ S1: begin
+ cpld_start = 1'b1;
+ cpld_done = 1'b0;
+ if (sampled_clk)
+ begin
+ // Found rising edge on cpld_clk.
+ if (count[2:0] == 3'b111)
+ // Its the last bit of a byte, send it out to the Wishbone bus.
+ begin
+ load_data_reg = 1'b1;
+ inc_count = 1'b1;
+ end
+ else
+ // Shift databit into LSB of shift register and increment count
+ begin
+ shift = 1'b1;
+ inc_count = 1'b1;
+ end // else: !if(count[2:0] == 3'b111)
+ next_state = S2;
+ end // if (sampled_clk)
+ else
+ next_state = S1;
+ end // case: S1
+
+ //
+ S2: begin
+ cpld_start = 1'b1;
+ cpld_done = 1'b0;
+ if (~sampled_clk)
+ // Found negative edge of clock
+ if (count[AWIDTH+2:3] == RAM_SIZE-1) // NOTE need to change this constant
+ // All firmware now downloaded
+ next_state = S3;
+ else
+ next_state = S1;
+ else
+ next_state = S2;
+ end // case: S2
+
+ // Now that terminal count is reached and all firmware is downloaded signal CPLD that download is done
+ // and that mode is now SPI mode.
+ S3: begin
+ if (sampled_clk)
+ begin
+ cpld_mode = 1'b1;
+ cpld_done = 1'b1;
+ next_state = S4;
+ end
+ else
+ next_state = S3;
+ end
+
+ // Search for negedge of cpld_clk whilst keeping done sequence asserted.
+ // Keep done assserted
+ S4: begin
+ cpld_mode = 1'b1;
+ cpld_done = 1'b1;
+ if (~sampled_clk)
+ next_state = S5;
+ else
+ next_state = S4;
+ end
+
+ // Search for posedge of cpld_clk whilst keeping done sequence asserted.
+ S5: begin
+ cpld_mode = 1'b1;
+ cpld_done = 1'b1;
+ if (sampled_clk)
+ next_state = S6;
+ else
+ next_state = S5;
+ end
+
+ // Stay in this state until reset/power down
+ S6: begin
+ ram_loader_done = 1'b1;
+ cpld_done = 1'b1;
+ cpld_mode = 1'b1;
+ next_state = S6;
+ end
+
+ endcase // case(state)
+ end
+
+ always @(posedge dsp_clk or posedge ram_loader_rst)
+ if (ram_loader_rst)
+ wb_state <= WB_IDLE;
+ else
+ wb_state <= wb_next_state;
+
+ reg do_write;
+ wire empty, full;
+
+ always @*
+ begin
+ wb_next_state = wb_state;
+ do_write = 1'b0;
+
+ case (wb_state) //synthesis full_case parallel_case
+ //
+ WB_IDLE: begin
+ if (load_data_reg)
+ // Data reg will load ready to write wishbone @ next clock edge
+ wb_next_state = WB_WRITE;
+ else
+ wb_next_state = WB_IDLE;
+ end
+
+ // Drive address and data onto wishbone.
+ WB_WRITE: begin
+ do_write = 1'b1;
+ if (~full)
+ wb_next_state = WB_IDLE;
+ else
+ wb_next_state = WB_WRITE;
+ end
+
+ endcase // case(wb_state)
+ end // always @ *
+
+ wire [1:0] count_out;
+ wire [7:0] data_out;
+
+ fifo_xlnx_16x40_2clk crossclk
+ (.rst(ram_loader_rst),
+ .wr_clk(dsp_clk), .din({count[4:3],count[AWIDTH+2:3],data_reg}), .wr_en(do_write), .full(full),
+ .rd_clk(wb_clk), .dout({count_out,wb_adr,data_out}), .rd_en(~empty), .empty(empty));
+
+ assign wb_dat = {4{data_out}};
+
+ always @*
+ case(count_out[1:0]) //synthesis parallel_case full_case
+ 2'b00 : wb_sel = 4'b1000;
+ 2'b01 : wb_sel = 4'b0100;
+ 2'b10 : wb_sel = 4'b0010;
+ 2'b11 : wb_sel = 4'b0001;
+ endcase
+
+ assign wb_we = ~empty;
+ assign wb_stb = ~empty;
+
+endmodule // ram_loader
diff --git a/fpga/usrp2/control_lib/ram_wb_harvard.v b/fpga/usrp2/control_lib/ram_wb_harvard.v
new file mode 100644
index 000000000..8d5a45247
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_wb_harvard.v
@@ -0,0 +1,103 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Dual ported RAM for Harvard architecture processors
+// Does no forwarding
+// Addresses are byte-oriented, so botton 2 address bits are ignored. FIXME
+// AWIDTH of 13 gives 8K bytes. For Spartan 3, if the total RAM size is not a
+// multiple of 8K then BRAM space is wasted
+
+module ram_wb_harvard #(parameter AWIDTH=13)
+ (input wb_clk_i,
+ input wb_rst_i,
+
+ input [AWIDTH-1:0] iwb_adr_i,
+ input [31:0] iwb_dat_i,
+ output reg [31:0] iwb_dat_o,
+ input iwb_we_i,
+ output reg iwb_ack_o,
+ input iwb_stb_i,
+ input [3:0] iwb_sel_i,
+
+ input [AWIDTH-1:0] dwb_adr_i,
+ input [31:0] dwb_dat_i,
+ output reg [31:0] dwb_dat_o,
+ input dwb_we_i,
+ output reg dwb_ack_o,
+ input dwb_stb_i,
+ input [3:0] dwb_sel_i);
+
+ reg [7:0] ram0 [0:(1<<(AWIDTH-2))-1];
+ reg [7:0] ram1 [0:(1<<(AWIDTH-2))-1];
+ reg [7:0] ram2 [0:(1<<(AWIDTH-2))-1];
+ reg [7:0] ram3 [0:(1<<(AWIDTH-2))-1];
+
+ // Instruction Read Port
+ always @(posedge wb_clk_i)
+ iwb_ack_o <= iwb_stb_i & ~iwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ iwb_dat_o[31:24] <= ram3[iwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ iwb_dat_o[23:16] <= ram2[iwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ iwb_dat_o[15:8] <= ram1[iwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ iwb_dat_o[7:0] <= ram0[iwb_adr_i[AWIDTH-1:2]];
+
+ always @(posedge wb_clk_i)
+ if(iwb_we_i & iwb_stb_i & iwb_sel_i[3])
+ ram3[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[31:24];
+ always @(posedge wb_clk_i)
+ if(iwb_we_i & iwb_stb_i & iwb_sel_i[2])
+ ram2[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[23:16];
+ always @(posedge wb_clk_i)
+ if(iwb_we_i & iwb_stb_i & iwb_sel_i[1])
+ ram1[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[15:8];
+ always @(posedge wb_clk_i)
+ if(iwb_we_i & iwb_stb_i & iwb_sel_i[0])
+ ram0[iwb_adr_i[AWIDTH-1:2]] <= iwb_dat_i[7:0];
+
+ // Data Port
+ always @(posedge wb_clk_i)
+ dwb_ack_o <= dwb_stb_i & ~dwb_ack_o;
+
+ always @(posedge wb_clk_i)
+ dwb_dat_o[31:24] <= ram3[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ dwb_dat_o[23:16] <= ram2[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ dwb_dat_o[15:8] <= ram1[dwb_adr_i[AWIDTH-1:2]];
+ always @(posedge wb_clk_i)
+ dwb_dat_o[7:0] <= ram0[dwb_adr_i[AWIDTH-1:2]];
+
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[3])
+ ram3[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[31:24];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[2])
+ ram2[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[23:16];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[1])
+ ram1[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[15:8];
+ always @(posedge wb_clk_i)
+ if(dwb_we_i & dwb_stb_i & dwb_sel_i[0])
+ ram0[dwb_adr_i[AWIDTH-1:2]] <= dwb_dat_i[7:0];
+
+endmodule // ram_wb_harvard
+
diff --git a/fpga/usrp2/control_lib/reset_sync.v b/fpga/usrp2/control_lib/reset_sync.v
new file mode 100644
index 000000000..304aba106
--- /dev/null
+++ b/fpga/usrp2/control_lib/reset_sync.v
@@ -0,0 +1,33 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module reset_sync
+ (input clk,
+ input reset_in,
+ output reg reset_out);
+
+ reg reset_int;
+
+ always @(posedge clk or posedge reset_in)
+ if(reset_in)
+ {reset_out,reset_int} <= 2'b11;
+ else
+ {reset_out,reset_int} <= {reset_int,1'b0};
+
+endmodule // reset_sync
diff --git a/fpga/usrp2/control_lib/s3a_icap_wb.v b/fpga/usrp2/control_lib/s3a_icap_wb.v
new file mode 100644
index 000000000..e49b56cff
--- /dev/null
+++ b/fpga/usrp2/control_lib/s3a_icap_wb.v
@@ -0,0 +1,76 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module s3a_icap_wb
+ (input clk, input reset,
+ input cyc_i, input stb_i, input we_i, output ack_o,
+ input [31:0] dat_i, output [31:0] dat_o);//, output [31:0] debug_out);
+
+ assign dat_o[31:8] = 24'd0;
+
+ wire BUSY, CE, WRITE, ICAPCLK;
+
+ //changed this to gray-ish code to prevent glitching
+ reg [2:0] icap_state;
+ localparam ICAP_IDLE = 0;
+ localparam ICAP_WR0 = 1;
+ localparam ICAP_WR1 = 5;
+ localparam ICAP_RD0 = 2;
+ localparam ICAP_RD1 = 3;
+
+ always @(posedge clk)
+ if(reset)
+ icap_state <= ICAP_IDLE;
+ else
+ case(icap_state)
+ ICAP_IDLE :
+ begin
+ if(stb_i & cyc_i)
+ if(we_i)
+ icap_state <= ICAP_WR0;
+ else
+ icap_state <= ICAP_RD0;
+ end
+ ICAP_WR0 :
+ icap_state <= ICAP_WR1;
+ ICAP_WR1 :
+ icap_state <= ICAP_IDLE;
+ ICAP_RD0 :
+ icap_state <= ICAP_RD1;
+ ICAP_RD1 :
+ icap_state <= ICAP_IDLE;
+ endcase // case (icap_state)
+
+ assign WRITE = (icap_state == ICAP_WR0) | (icap_state == ICAP_WR1);
+ assign CE = (icap_state == ICAP_WR0) | (icap_state == ICAP_RD0);
+ assign ICAPCLK = CE & (~clk);
+
+ assign ack_o = (icap_state == ICAP_WR1) | (icap_state == ICAP_RD1);
+ //assign debug_out = {17'd0, BUSY, dat_i[7:0], ~CE, ICAPCLK, ~WRITE, icap_state};
+
+ ICAP_SPARTAN3A ICAP_SPARTAN3A_inst
+ (.BUSY(BUSY), // Busy output
+ .O(dat_o[7:0]), // 32-bit data output
+ .CE(~CE), // Clock enable input
+ .CLK(ICAPCLK), // Clock input
+ .I(dat_i[7:0]), // 32-bit data input
+ .WRITE(~WRITE) // Write input
+ );
+
+endmodule // s3a_icap_wb
diff --git a/fpga/usrp2/control_lib/sd_spi.v b/fpga/usrp2/control_lib/sd_spi.v
new file mode 100644
index 000000000..fa998d19a
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi.v
@@ -0,0 +1,87 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+module sd_spi
+ (input clk,
+ input rst,
+
+ // SD Card interface
+ output reg sd_clk,
+ output sd_mosi,
+ input sd_miso,
+
+ // Controls
+ input [7:0] clk_div,
+ input [7:0] send_dat,
+ output [7:0] rcv_dat,
+ input go,
+ output ready);
+
+ reg [7:0] clk_ctr;
+ reg [3:0] bit_ctr;
+
+ wire bit_ready = (clk_ctr == 8'd0);
+ wire bit_busy = (clk_ctr != 8'd0);
+ wire bit_done = (clk_ctr == clk_div);
+
+ wire send_clk_hi = (clk_ctr == (clk_div>>1));
+ wire latch_dat = (clk_ctr == (clk_div - 8'd2));
+ wire send_clk_lo = (clk_ctr == (clk_div - 8'd1));
+
+ wire send_bit = (bit_ready && (bit_ctr != 0));
+ assign ready = (bit_ctr == 0);
+
+ always @(posedge clk)
+ if(rst)
+ clk_ctr <= 0;
+ else if(bit_done)
+ clk_ctr <= 0;
+ else if(bit_busy)
+ clk_ctr <= clk_ctr + 1;
+ else if(send_bit)
+ clk_ctr <= 1;
+
+ always @(posedge clk)
+ if(rst)
+ sd_clk <= 0;
+ else if(send_clk_hi)
+ sd_clk <= 1;
+ else if(send_clk_lo)
+ sd_clk <= 0;
+
+ always @(posedge clk)
+ if(rst)
+ bit_ctr <= 0;
+ else if(bit_done)
+ if(bit_ctr == 4'd8)
+ bit_ctr <= 0;
+ else
+ bit_ctr <= bit_ctr + 1;
+ else if(bit_ready & go)
+ bit_ctr <= 1;
+
+ reg [7:0] shift_reg;
+ always @(posedge clk)
+ if(go)
+ shift_reg <= send_dat;
+ else if(latch_dat)
+ shift_reg <= {shift_reg[6:0],sd_miso};
+
+ assign sd_mosi = shift_reg[7];
+ assign rcv_dat = shift_reg;
+
+endmodule // sd_spi
diff --git a/fpga/usrp2/control_lib/sd_spi_tb.v b/fpga/usrp2/control_lib/sd_spi_tb.v
new file mode 100644
index 000000000..2b5ae083f
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi_tb.v
@@ -0,0 +1,57 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module sd_spi_tb;
+
+ reg clk = 0;
+ always #5 clk = ~clk;
+ reg rst = 1;
+ initial #32 rst = 0;
+
+ wire sd_clk, sd_mosi, sd_miso;
+ wire [7:0] clk_div = 12;
+ wire [7:0] send_dat = 23;
+ wire [7:0] rcv_dat;
+
+ wire ready;
+ reg go = 0;
+ initial
+ begin
+ repeat (100)
+ @(posedge clk);
+ go <= 1;
+ @(posedge clk);
+ go <= 0;
+ end
+
+ sd_spi dut(.clk(clk),.rst(rst),
+ .sd_clk(sd_clk),.sd_mosi(sd_mosi),.sd_miso(sd_miso),
+ .clk_div(clk_div),.send_dat(send_dat),.rcv_dat(rcv_dat),
+ .go(go),.ready(ready) );
+
+ initial
+ begin
+ $dumpfile("sd_spi_tb.vcd");
+ $dumpvars(0,sd_spi_tb);
+ end
+
+ initial
+ #10000 $finish();
+
+endmodule // sd_spi_tb
diff --git a/fpga/usrp2/control_lib/sd_spi_wb.v b/fpga/usrp2/control_lib/sd_spi_wb.v
new file mode 100644
index 000000000..b09debd70
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi_wb.v
@@ -0,0 +1,93 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Wishbone module for spi communications with an SD Card
+// The programming interface is simple --
+// Write the desired clock divider to address 1 (should be 1 or higher)
+// Status is in address 0. A 1 indicates the last transaction is done and it is safe to
+// send another
+// Writing a byte to address 2 sends that byte over SPI. When it is done,
+// status (addr 0) goes high again, and the received byte can be read from address 3.
+
+module sd_spi_wb
+ (input clk,
+ input rst,
+
+ // SD Card interface
+ output sd_clk,
+ output sd_csn,
+ output sd_mosi,
+ input sd_miso,
+
+ input wb_cyc_i,
+ input wb_stb_i,
+ input wb_we_i,
+ input [1:0] wb_adr_i,
+ input [7:0] wb_dat_i,
+ output reg [7:0] wb_dat_o,
+ output reg wb_ack_o);
+
+ localparam ADDR_STATUS = 0;
+ localparam ADDR_CLKDIV = 1;
+ localparam ADDR_WRITE = 2;
+ localparam ADDR_READ = 3;
+
+ wire [7:0] status, rcv_dat;
+ reg [7:0] clkdiv;
+ wire ready;
+ reg ack_d1;
+
+ reg cs_reg;
+ assign sd_csn = ~cs_reg; // FIXME
+
+ always @(posedge clk)
+ if(rst) ack_d1 <= 0;
+ else ack_d1 <= wb_ack_o;
+
+ always @(posedge clk)
+ if(rst) wb_ack_o <= 0;
+ else wb_ack_o <= wb_cyc_i & wb_stb_i & ~ack_d1;
+
+ always @(posedge clk)
+ case(wb_adr_i)
+ ADDR_STATUS : wb_dat_o <= {7'd0,ready};
+ ADDR_CLKDIV : wb_dat_o <= clkdiv;
+ ADDR_READ : wb_dat_o <= rcv_dat;
+ default : wb_dat_o <= 0;
+ endcase // case(wb_adr_i)
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ clkdiv <= 200;
+ cs_reg <= 0;
+ end
+ else if(wb_we_i & wb_stb_i & wb_cyc_i & wb_ack_o)
+ case(wb_adr_i)
+ ADDR_STATUS : cs_reg <= wb_dat_i;
+ ADDR_CLKDIV : clkdiv <= wb_dat_i;
+ endcase // case(wb_adr_i)
+
+ wire go = wb_we_i & wb_stb_i & wb_cyc_i & wb_ack_o & (wb_adr_i == ADDR_WRITE);
+
+ sd_spi sd_spi(.clk(clk),.rst(rst),
+ .sd_clk(sd_clk),.sd_mosi(sd_mosi),.sd_miso(sd_miso),
+ .clk_div(clkdiv),.send_dat(wb_dat_i),.rcv_dat(rcv_dat),
+ .go(go),.ready(ready) );
+
+endmodule // sd_spi_wb
diff --git a/fpga/usrp2/control_lib/setting_reg.v b/fpga/usrp2/control_lib/setting_reg.v
new file mode 100644
index 000000000..e4c84d910
--- /dev/null
+++ b/fpga/usrp2/control_lib/setting_reg.v
@@ -0,0 +1,42 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module setting_reg
+ #(parameter my_addr = 0,
+ parameter width = 32,
+ parameter at_reset=32'd0)
+ (input clk, input rst, input strobe, input wire [7:0] addr,
+ input wire [31:0] in, output reg [width-1:0] out, output reg changed);
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ out <= at_reset;
+ changed <= 1'b0;
+ end
+ else
+ if(strobe & (my_addr==addr))
+ begin
+ out <= in;
+ changed <= 1'b1;
+ end
+ else
+ changed <= 1'b0;
+
+endmodule // setting_reg
diff --git a/fpga/usrp2/control_lib/settings_bus.v b/fpga/usrp2/control_lib/settings_bus.v
new file mode 100644
index 000000000..e2ea7e44b
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus.v
@@ -0,0 +1,58 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Grab settings off the wishbone bus, send them out to our simpler bus on the fast clock
+
+module settings_bus
+ #(parameter AWIDTH=16, parameter DWIDTH=32)
+ (input wb_clk,
+ input wb_rst,
+ input [AWIDTH-1:0] wb_adr_i,
+ input [DWIDTH-1:0] wb_dat_i,
+ input wb_stb_i,
+ input wb_we_i,
+ output reg wb_ack_o,
+ output reg strobe,
+ output reg [7:0] addr,
+ output reg [31:0] data);
+
+ reg stb_int, stb_int_d1;
+
+ always @(posedge wb_clk)
+ if(wb_rst)
+ begin
+ strobe <= 1'b0;
+ addr <= 8'd0;
+ data <= 32'd0;
+ end
+ else if(wb_we_i & wb_stb_i & ~wb_ack_o)
+ begin
+ strobe <= 1'b1;
+ addr <= wb_adr_i[9:2];
+ data <= wb_dat_i;
+ end
+ else
+ strobe <= 1'b0;
+
+ always @(posedge wb_clk)
+ if(wb_rst)
+ wb_ack_o <= 0;
+ else
+ wb_ack_o <= wb_stb_i & ~wb_ack_o;
+
+endmodule // settings_bus
diff --git a/fpga/usrp2/control_lib/settings_bus_16LE.v b/fpga/usrp2/control_lib/settings_bus_16LE.v
new file mode 100644
index 000000000..7c42a0870
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus_16LE.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// Grab settings off the wishbone bus, send them out to settings bus
+// 16 bits little endian, but all registers need to be written 32 bits at a time.
+// This means that you write the low 16 bits first and then the high 16 bits.
+// The setting regs are strobed when the high 16 bits are written
+
+module settings_bus_16LE
+ #(parameter AWIDTH=16, RWIDTH=8)
+ (input wb_clk,
+ input wb_rst,
+ input [AWIDTH-1:0] wb_adr_i,
+ input [15:0] wb_dat_i,
+ input wb_stb_i,
+ input wb_we_i,
+ output reg wb_ack_o,
+ output strobe,
+ output reg [7:0] addr,
+ output reg [31:0] data);
+
+ reg stb_int;
+
+ always @(posedge wb_clk)
+ if(wb_rst)
+ begin
+ stb_int <= 1'b0;
+ addr <= 8'd0;
+ data <= 32'd0;
+ end
+ else if(wb_we_i & wb_stb_i)
+ begin
+ addr <= wb_adr_i[RWIDTH+1:2]; // Zero pad high bits
+ if(wb_adr_i[1])
+ begin
+ stb_int <= 1'b1; // We now have both halves
+ data[31:16] <= wb_dat_i;
+ end
+ else
+ begin
+ stb_int <= 1'b0; // Don't strobe, we need other half
+ data[15:0] <= wb_dat_i;
+ end
+ end
+ else
+ stb_int <= 1'b0;
+
+ always @(posedge wb_clk)
+ if(wb_rst)
+ wb_ack_o <= 0;
+ else
+ wb_ack_o <= wb_stb_i & ~wb_ack_o;
+
+ assign strobe = stb_int & wb_ack_o;
+
+endmodule // settings_bus_16LE
diff --git a/fpga/usrp2/control_lib/settings_bus_crossclock.v b/fpga/usrp2/control_lib/settings_bus_crossclock.v
new file mode 100644
index 000000000..a61ee8fad
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus_crossclock.v
@@ -0,0 +1,38 @@
+//
+// Copyright 2011-2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// This module takes the settings bus on one clock domain and crosses it over to another domain
+// Typically it will be used with the input settings bus on the wishbone clock, and either
+// the system or dsp clock on the output side
+
+module settings_bus_crossclock
+ #(parameter FLOW_CTRL=0)
+ (input clk_i, input rst_i, input set_stb_i, input [7:0] set_addr_i, input [31:0] set_data_i,
+ input clk_o, input rst_o, output set_stb_o, output [7:0] set_addr_o, output [31:0] set_data_o, input blocked);
+
+ wire full, empty;
+
+ fifo_xlnx_16x40_2clk settings_fifo
+ (.rst(rst_i),
+ .wr_clk(clk_i), .din({set_addr_i,set_data_i}), .wr_en(set_stb_i & ~full), .full(full),
+ .rd_clk(clk_o), .dout({set_addr_o,set_data_o}), .rd_en(set_stb_o), .empty(empty));
+
+ assign set_stb_o = ~empty & (~blocked | ~FLOW_CTRL);
+
+endmodule // settings_bus_crossclock
diff --git a/fpga/usrp2/control_lib/settings_fifo_ctrl.v b/fpga/usrp2/control_lib/settings_fifo_ctrl.v
new file mode 100644
index 000000000..d0add1c72
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_fifo_ctrl.v
@@ -0,0 +1,428 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// A settings and readback bus controlled via fifo36 interface
+
+module settings_fifo_ctrl
+ #(
+ parameter XPORT_HDR = 1, //extra transport hdr line
+ parameter PROT_DEST = 0, //protocol framer destination
+ parameter PROT_HDR = 1, //needs a protocol header?
+ parameter ACK_SID = 0 //stream ID for packet ACK
+ )
+ (
+ //clock and synchronous reset for all interfaces
+ input clock, input reset, input clear,
+
+ //current system time
+ input [63:0] vita_time,
+
+ //ready signal for multiple peripherals
+ input perfs_ready,
+
+ //input fifo36 interface control
+ input [35:0] in_data, input in_valid, output in_ready,
+
+ //output fifo36 interface status
+ output [35:0] out_data, output out_valid, input out_ready,
+
+ //32-bit settings bus outputs
+ output strobe, output [7:0] addr, output [31:0] data,
+
+ //16X 32-bit inputs for readback
+ input [31:0] word00,
+ input [31:0] word01,
+ input [31:0] word02,
+ input [31:0] word03,
+ input [31:0] word04,
+ input [31:0] word05,
+ input [31:0] word06,
+ input [31:0] word07,
+ input [31:0] word08,
+ input [31:0] word09,
+ input [31:0] word10,
+ input [31:0] word11,
+ input [31:0] word12,
+ input [31:0] word13,
+ input [31:0] word14,
+ input [31:0] word15,
+
+ //debug output
+ output [31:0] debug
+ );
+
+ wire reading = in_valid && in_ready;
+ wire writing = out_valid && out_ready;
+
+ //------------------------------------------------------------------
+ //-- The command fifo:
+ //-- Stores an individual register access command per line.
+ //------------------------------------------------------------------
+ wire [63:0] in_command_ticks, out_command_ticks;
+ wire [31:0] in_command_hdr, out_command_hdr;
+ wire [31:0] in_command_data, out_command_data;
+ wire in_command_has_time, out_command_has_time;
+ wire command_fifo_full, command_fifo_empty;
+ wire command_fifo_read, command_fifo_write;
+
+ wire [128:0] fifo2_datain, fifo3_datain, fifo4_datain;
+ wire fifo1_empty, fifo2_empty, fifo3_empty;
+ wire fifo2_full, fifo3_full, fifo4_full;
+ wire fifo1_to_fifo2, fifo2_to_fifo3, fifo3_to_fifo4;
+
+ shortfifo #(.WIDTH(129)) command_fifo (
+ .clk(clock), .rst(reset), .clear(clear),
+ .datain({in_command_ticks, in_command_hdr, in_command_data, in_command_has_time}),
+ .dataout(fifo2_datain),
+ .write(command_fifo_write), .full(command_fifo_full), //input interface
+ .empty(fifo1_empty), .read(fifo1_to_fifo2) //output interface
+ );
+
+ shortfifo #(.WIDTH(129)) command_fifo2 (
+ .clk(clock), .rst(reset), .clear(clear),
+ .datain(fifo2_datain),
+ .dataout(fifo3_datain),
+ .write(fifo1_to_fifo2), .full(fifo2_full), //input interface
+ .empty(fifo2_empty), .read(fifo2_to_fifo3) //output interface
+ );
+
+ shortfifo #(.WIDTH(129)) command_fifo3 (
+ .clk(clock), .rst(reset), .clear(clear),
+ .datain(fifo3_datain),
+ .dataout(fifo4_datain),
+ .write(fifo2_to_fifo3), .full(fifo3_full), //input interface
+ .empty(fifo3_empty), .read(fifo3_to_fifo4) //output interface
+ );
+
+ shortfifo #(.WIDTH(129)) command_fifo4 (
+ .clk(clock), .rst(reset), .clear(clear),
+ .datain(fifo4_datain),
+ .dataout({out_command_ticks, out_command_hdr, out_command_data, out_command_has_time}),
+ .write(fifo3_to_fifo4), .full(fifo4_full), //input interface
+ .empty(command_fifo_empty), .read(command_fifo_read) //output interface
+ );
+
+ assign fifo1_to_fifo2 = ~fifo2_full & ~fifo1_empty;
+ assign fifo2_to_fifo3 = ~fifo3_full & ~fifo2_empty;
+ assign fifo3_to_fifo4 = ~fifo4_full & ~fifo3_empty;
+
+ //------------------------------------------------------------------
+ //-- The result fifo:
+ //-- Stores an individual result of a command per line.
+ //------------------------------------------------------------------
+ wire [31:0] in_result_hdr, out_result_hdr;
+ wire [31:0] in_result_data, out_result_data;
+ wire result_fifo_full, result_fifo_empty;
+ wire result_fifo_read, result_fifo_write;
+
+ shortfifo #(.WIDTH(64)) result_fifo (
+ .clk(clock), .rst(reset), .clear(clear),
+ .datain({in_result_hdr, in_result_data}),
+ .dataout({out_result_hdr, out_result_data}),
+ .write(result_fifo_write), .full(result_fifo_full), //input interface
+ .empty(result_fifo_empty), .read(result_fifo_read) //output interface
+ );
+
+ //------------------------------------------------------------------
+ //-- Input state machine:
+ //-- Read input packet and fill a command fifo entry.
+ //------------------------------------------------------------------
+ localparam READ_LINE0 = 0;
+ localparam VITA_HDR = 1;
+ localparam VITA_SID = 2;
+ localparam VITA_CID0 = 3;
+ localparam VITA_CID1 = 4;
+ localparam VITA_TSI = 5;
+ localparam VITA_TSF0 = 6;
+ localparam VITA_TSF1 = 7;
+ localparam READ_HDR = 8;
+ localparam READ_DATA = 9;
+ localparam WAIT_EOF = 10;
+ localparam STORE_CMD = 11;
+
+ localparam START_STATE = (XPORT_HDR)? READ_LINE0 : VITA_HDR;
+
+ reg [4:0] in_state;
+
+ //holdover from current read inputs
+ reg [31:0] in_data_reg, in_hdr_reg;
+ reg [63:0] in_ticks_reg;
+ wire has_sid = in_data[28];
+ wire has_cid = in_data[27];
+ wire has_tsi = in_data[23:22] != 0;
+ wire has_tsf = in_data[21:20] != 0;
+ reg has_sid_reg, has_cid_reg, has_tsi_reg, has_tsf_reg;
+
+ assign in_ready = (in_state < STORE_CMD);
+ assign command_fifo_write = (in_state == STORE_CMD);
+ assign in_command_ticks = in_ticks_reg;
+ assign in_command_data = in_data_reg;
+ assign in_command_hdr = in_hdr_reg;
+ assign in_command_has_time = has_tsf_reg;
+
+ always @(posedge clock) begin
+ if (reset) begin
+ in_state <= START_STATE;
+ end
+ else begin
+ case (in_state)
+
+ READ_LINE0: begin
+ if (reading) in_state <= VITA_HDR;
+ end
+
+ VITA_HDR: begin
+ if (reading) begin
+ if (has_sid) in_state <= VITA_SID;
+ else if (has_cid) in_state <= VITA_CID0;
+ else if (has_tsi) in_state <= VITA_TSI;
+ else if (has_tsf) in_state <= VITA_TSF0;
+ else in_state <= READ_HDR;
+ end
+ has_sid_reg <= has_sid;
+ has_cid_reg <= has_cid;
+ has_tsi_reg <= has_tsi;
+ has_tsf_reg <= has_tsf;
+ end
+
+ VITA_SID: begin
+ if (reading) begin
+ if (has_cid_reg) in_state <= VITA_CID0;
+ else if (has_tsi_reg) in_state <= VITA_TSI;
+ else if (has_tsf_reg) in_state <= VITA_TSF0;
+ else in_state <= READ_HDR;
+ end
+ end
+
+ VITA_CID0: begin
+ if (reading) in_state <= VITA_CID1;
+ end
+
+ VITA_CID1: begin
+ if (reading) begin
+ if (has_tsi_reg) in_state <= VITA_TSI;
+ else if (has_tsf_reg) in_state <= VITA_TSF0;
+ else in_state <= READ_HDR;
+ end
+ end
+
+ VITA_TSI: begin
+ if (reading) begin
+ if (has_tsf_reg) in_state <= VITA_TSF0;
+ else in_state <= READ_HDR;
+ end
+ end
+
+ VITA_TSF0: begin
+ if (reading) in_state <= VITA_TSF1;
+ in_ticks_reg[63:32] <= in_data;
+ end
+
+ VITA_TSF1: begin
+ if (reading) in_state <= READ_HDR;
+ in_ticks_reg[31:0] <= in_data;
+ end
+
+ READ_HDR: begin
+ if (reading) in_state <= READ_DATA;
+ in_hdr_reg <= in_data[31:0];
+ end
+
+ READ_DATA: begin
+ if (reading) in_state <= (in_data[33])? STORE_CMD : WAIT_EOF;
+ in_data_reg <= in_data[31:0];
+ end
+
+ WAIT_EOF: begin
+ if (reading && in_data[33]) in_state <= STORE_CMD;
+ end
+
+ STORE_CMD: begin
+ if (~command_fifo_full) in_state <= START_STATE;
+ end
+
+ endcase //in_state
+ end
+ end
+
+ //------------------------------------------------------------------
+ //-- Command state machine:
+ //-- Read a command fifo entry, act on it, produce result.
+ //------------------------------------------------------------------
+ localparam LOAD_CMD = 0;
+ localparam EVENT_CMD = 1;
+
+ reg cmd_state;
+ reg [31:0] rb_data;
+
+ reg [63:0] command_ticks_reg;
+ reg [31:0] command_hdr_reg;
+ reg [31:0] command_data_reg;
+
+ reg [63:0] vita_time_reg;
+ always @(posedge clock)
+ vita_time_reg <= vita_time;
+
+ wire late;
+ `ifndef FIFO_CTRL_NO_TIME
+ time_compare time_compare(
+ .time_now(vita_time_reg), .trigger_time(command_ticks_reg), .late(late));
+ `else
+ assign late = 1;
+ `endif
+
+ //action occurs in the event state and when there is fifo space (should always be true)
+ //the third condition is that all peripherals in the perfs signal are ready/active high
+ //the fourth condition is that is an event time has been set, action is delayed until that time
+ wire time_ready = (out_command_has_time)? late : 1;
+ wire action = (cmd_state == EVENT_CMD) && ~result_fifo_full && perfs_ready && time_ready;
+
+ assign command_fifo_read = action;
+ assign result_fifo_write = action;
+ assign in_result_hdr = command_hdr_reg;
+ assign in_result_data = rb_data;
+
+ always @(posedge clock) begin
+ if (reset) begin
+ cmd_state <= LOAD_CMD;
+ end
+ else begin
+ case (cmd_state)
+
+ LOAD_CMD: begin
+ if (~command_fifo_empty) cmd_state <= EVENT_CMD;
+ command_ticks_reg <= out_command_ticks;
+ command_hdr_reg <= out_command_hdr;
+ command_data_reg <= out_command_data;
+ end
+
+ EVENT_CMD: begin // poking and peeking happens here!
+ if (action || clear) cmd_state <= LOAD_CMD;
+ end
+
+ endcase //cmd_state
+ end
+ end
+
+ //------------------------------------------------------------------
+ //-- assign to settings bus interface
+ //------------------------------------------------------------------
+ reg strobe_reg;
+ assign strobe = strobe_reg;
+ assign data = command_data_reg;
+ assign addr = command_hdr_reg[7:0];
+ wire poke = command_hdr_reg[8];
+
+ always @(posedge clock) begin
+ if (reset || clear) strobe_reg <= 0;
+ else strobe_reg <= action && poke;
+ end
+
+ //------------------------------------------------------------------
+ //-- readback mux
+ //------------------------------------------------------------------
+ always @(posedge clock) begin
+ case (out_command_hdr[3:0])
+ 0 : rb_data <= word00;
+ 1 : rb_data <= word01;
+ 2 : rb_data <= word02;
+ 3 : rb_data <= word03;
+ 4 : rb_data <= word04;
+ 5 : rb_data <= word05;
+ 6 : rb_data <= word06;
+ 7 : rb_data <= word07;
+ 8 : rb_data <= word08;
+ 9 : rb_data <= word09;
+ 10: rb_data <= word10;
+ 11: rb_data <= word11;
+ 12: rb_data <= word12;
+ 13: rb_data <= word13;
+ 14: rb_data <= word14;
+ 15: rb_data <= word15;
+ endcase // case(addr_reg[3:0])
+ end
+
+ //------------------------------------------------------------------
+ //-- Output state machine:
+ //-- Read a command fifo entry, act on it, produce ack packet.
+ //------------------------------------------------------------------
+ localparam WRITE_PROT_HDR = 0;
+ localparam WRITE_VRT_HDR = 1;
+ localparam WRITE_VRT_SID = 2;
+ localparam WRITE_RB_HDR = 3;
+ localparam WRITE_RB_DATA = 4;
+
+ //the state for the start of packet condition
+ localparam WRITE_PKT_HDR = (PROT_HDR)? WRITE_PROT_HDR : WRITE_VRT_HDR;
+
+ reg [2:0] out_state;
+
+ assign out_valid = ~result_fifo_empty;
+ assign result_fifo_read = out_data[33] && writing;
+
+ always @(posedge clock) begin
+ if (reset) begin
+ out_state <= WRITE_PKT_HDR;
+ end
+ else if (writing && out_data[33]) begin
+ out_state <= WRITE_PKT_HDR;
+ end
+ else if (writing) begin
+ out_state <= out_state + 1;
+ end
+ end
+
+ //------------------------------------------------------------------
+ //-- assign to output fifo interface
+ //------------------------------------------------------------------
+ wire [31:0] prot_hdr;
+ assign prot_hdr[15:0] = 16; //bytes in proceeding vita packet
+ assign prot_hdr[16] = 1; //yes frame
+ assign prot_hdr[18:17] = PROT_DEST;
+ assign prot_hdr[31:19] = 0; //nothing
+
+ reg [31:0] out_data_int;
+ always @* begin
+ case (out_state)
+ WRITE_PROT_HDR: out_data_int <= prot_hdr;
+ WRITE_VRT_HDR: out_data_int <= {12'b010100000000, out_result_hdr[19:16], 2'b0, prot_hdr[15:2]};
+ WRITE_VRT_SID: out_data_int <= ACK_SID;
+ WRITE_RB_HDR: out_data_int <= out_result_hdr;
+ WRITE_RB_DATA: out_data_int <= out_result_data;
+ default: out_data_int <= 0;
+ endcase //state
+ end
+
+ assign out_data[35:34] = 2'b0;
+ assign out_data[33] = (out_state == WRITE_RB_DATA);
+ assign out_data[32] = (out_state == WRITE_PKT_HDR);
+ assign out_data[31:0] = out_data_int;
+
+ //------------------------------------------------------------------
+ //-- debug outputs
+ //------------------------------------------------------------------
+ assign debug = {
+ in_state, out_state, //8
+ in_valid, in_ready, in_data[33:32], //4
+ out_valid, out_ready, out_data[33:32], //4
+ command_fifo_empty, command_fifo_full, //2
+ command_fifo_read, command_fifo_write, //2
+ addr, //8
+ strobe_reg, strobe, poke, out_command_has_time //4
+ };
+
+endmodule //settings_fifo_ctrl
diff --git a/fpga/usrp2/control_lib/shortfifo.v b/fpga/usrp2/control_lib/shortfifo.v
new file mode 100644
index 000000000..c7c916375
--- /dev/null
+++ b/fpga/usrp2/control_lib/shortfifo.v
@@ -0,0 +1,104 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module shortfifo
+ #(parameter WIDTH=32)
+ (input clk, input rst,
+ input [WIDTH-1:0] datain,
+ output [WIDTH-1:0] dataout,
+ input read,
+ input write,
+ input clear,
+ output reg full,
+ output reg empty,
+ output reg [4:0] space,
+ output reg [4:0] occupied);
+
+ reg [3:0] a;
+ genvar i;
+
+ generate
+ for (i=0;i<WIDTH;i=i+1)
+ begin : gen_srl16
+ SRL16E
+ srl16e(.Q(dataout[i]),
+ .A0(a[0]),.A1(a[1]),.A2(a[2]),.A3(a[3]),
+ .CE(write),.CLK(clk),.D(datain[i]));
+ end
+ endgenerate
+
+ always @(posedge clk)
+ if(rst)
+ begin
+ a <= 0;
+ empty <= 1;
+ full <= 0;
+ end
+ else if(clear)
+ begin
+ a <= 0;
+ empty <= 1;
+ full<= 0;
+ end
+ else if(read & ~write)
+ begin
+ full <= 0;
+ if(a==0)
+ empty <= 1;
+ else
+ a <= a - 1;
+ end
+ else if(write & ~read)
+ begin
+ empty <= 0;
+ if(~empty)
+ a <= a + 1;
+ if(a == 14)
+ full <= 1;
+ end
+
+ // NOTE will fail if you write into a full fifo or read from an empty one
+
+ //////////////////////////////////////////////////////////////
+ // space and occupied are used for diagnostics, not
+ // guaranteed correct
+
+ //assign space = full ? 0 : empty ? 16 : 15-a;
+ //assign occupied = empty ? 0 : full ? 16 : a+1;
+
+ always @(posedge clk)
+ if(rst)
+ space <= 16;
+ else if(clear)
+ space <= 16;
+ else if(read & ~write)
+ space <= space + 1;
+ else if(write & ~read)
+ space <= space - 1;
+
+ always @(posedge clk)
+ if(rst)
+ occupied <= 0;
+ else if(clear)
+ occupied <= 0;
+ else if(read & ~write)
+ occupied <= occupied - 1;
+ else if(write & ~read)
+ occupied <= occupied + 1;
+
+endmodule // shortfifo
diff --git a/fpga/usrp2/control_lib/simple_i2c_core.v b/fpga/usrp2/control_lib/simple_i2c_core.v
new file mode 100644
index 000000000..9c61de8fb
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_i2c_core.v
@@ -0,0 +1,116 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Simple I2C core
+
+// Settings reg map:
+//
+// BASE+0 control register
+// byte0 - control bits, data byte, or command bits, prescaler
+// byte1 - what to do? (documented in cpp file)
+// write prescaler lo
+// write prescaler hi
+// write control
+// write data
+// write command
+// read data
+// read status
+//
+
+// Readback:
+//
+// byte0 has readback value based on the last read command
+//
+
+module simple_i2c_core
+ #(
+ //settings register base address
+ parameter BASE = 0,
+
+ //i2c line level at reset
+ parameter ARST_LVL = 1
+ )
+ (
+ //clock and synchronous reset
+ input clock, input reset,
+
+ //32-bit settings bus inputs
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //32-bit data readback
+ output reg [31:0] readback,
+
+ //read is high when i2c core can begin another transaction
+ output reg ready,
+
+ // I2C signals
+ // i2c clock line
+ input scl_pad_i, // SCL-line input
+ output scl_pad_o, // SCL-line output (always 1'b0)
+ output scl_padoen_o, // SCL-line output enable (active low)
+
+ // i2c data line
+ input sda_pad_i, // SDA-line input
+ output sda_pad_o, // SDA-line output (always 1'b0)
+ output sda_padoen_o, // SDA-line output enable (active low)
+
+ //optional debug output
+ output [31:0] debug
+ );
+
+ //declare command settings register
+ wire [7:0] sr_what, sr_data;
+ wire sr_changed;
+ setting_reg #(.my_addr(BASE+0),.width(16)) i2c_cmd_sr(
+ .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out({sr_what, sr_data}),.changed(sr_changed));
+
+ //declare wb interface signals
+ wire [2:0] wb_addr;
+ wire [7:0] wb_data_mosi;
+ wire [7:0] wb_data_miso;
+ wire wb_we, wb_stb, wb_cyc;
+ wire wb_ack;
+
+ //create wishbone-based i2c core
+ i2c_master_top #(.ARST_LVL(ARST_LVL)) i2c
+ (.wb_clk_i(clock),.wb_rst_i(reset),.arst_i(1'b0),
+ .wb_adr_i(wb_addr),.wb_dat_i(wb_data_mosi),.wb_dat_o(wb_data_miso),
+ .wb_we_i(wb_we),.wb_stb_i(wb_stb),.wb_cyc_i(wb_cyc),
+ .wb_ack_o(wb_ack),.wb_inta_o(),
+ .scl_pad_i(scl_pad_i),.scl_pad_o(scl_pad_o),.scl_padoen_o(scl_padoen_o),
+ .sda_pad_i(sda_pad_i),.sda_pad_o(sda_pad_o),.sda_padoen_o(sda_padoen_o) );
+
+ //not ready between setting register and wishbone ack
+ always @(posedge clock) begin
+ if (reset || wb_ack) ready <= 1;
+ else if (sr_changed) ready <= 0;
+ end
+
+ //register wishbone data on every ack
+ always @(posedge clock) begin
+ if (wb_ack) readback <= {24'b0, wb_data_miso};
+ end
+
+ //assign wishbone signals
+ assign wb_addr = sr_what[2:0];
+ assign wb_stb = sr_changed;
+ assign wb_we = wb_stb && sr_what[3];
+ assign wb_cyc = wb_stb;
+ assign wb_data_mosi = sr_data;
+
+endmodule //simple_i2c_core
diff --git a/fpga/usrp2/control_lib/simple_spi_core.v b/fpga/usrp2/control_lib/simple_spi_core.v
new file mode 100644
index 000000000..3c0ed60b9
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_spi_core.v
@@ -0,0 +1,214 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// Simple SPI core, the simplest, yet complete spi core I can think of
+
+// Settings register controlled.
+// 2 settings regs, control and data
+// 1 32-bit readback and status signal
+
+// Settings reg map:
+//
+// BASE+0 divider setting
+// bits [15:0] spi clock divider
+//
+// BASE+1 configuration input
+// bits [23:0] slave select, bit0 = slave0 enabled
+// bits [29:24] num bits (1 through 32)
+// bit [30] data input edge = in data bit latched on rising edge of clock
+// bit [31] data output edge = out data bit latched on rising edge of clock
+//
+// BASE+2 input data
+// Writing this register begins a spi transaction.
+// Bits are latched out from bit 0.
+// Therefore, load this register in reverse.
+//
+// Readback
+// Bits are latched into bit 0.
+// Therefore, data will be in-order.
+
+module simple_spi_core
+ #(
+ //settings register base address
+ parameter BASE = 0,
+
+ //width of serial enables (up to 24 is possible)
+ parameter WIDTH = 8,
+
+ //idle state of the spi clock
+ parameter CLK_IDLE = 0,
+
+ //idle state of the serial enables
+ parameter SEN_IDLE = 24'hffffff
+ )
+ (
+ //clock and synchronous reset
+ input clock, input reset,
+
+ //32-bit settings bus inputs
+ input set_stb, input [7:0] set_addr, input [31:0] set_data,
+
+ //32-bit data readback
+ output [31:0] readback,
+
+ //read is high when spi core can begin another transaction
+ output ready,
+
+ //spi interface, slave selects, clock, data in, data out
+ output [WIDTH-1:0] sen,
+ output sclk,
+ output mosi,
+ input miso,
+
+ //optional debug output
+ output [31:0] debug
+ );
+
+ wire [15:0] sclk_divider;
+ setting_reg #(.my_addr(BASE+0),.width(16)) divider_sr(
+ .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(sclk_divider),.changed());
+
+ wire [23:0] slave_select;
+ wire [5:0] num_bits;
+ wire datain_edge, dataout_edge;
+ setting_reg #(.my_addr(BASE+1),.width(32)) config_sr(
+ .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out({dataout_edge, datain_edge, num_bits, slave_select}),.changed());
+
+ wire [31:0] mosi_data;
+ wire trigger_spi;
+ setting_reg #(.my_addr(BASE+2),.width(32)) data_sr(
+ .clk(clock),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
+ .out(mosi_data),.changed(trigger_spi));
+
+ localparam WAIT_TRIG = 0;
+ localparam PRE_IDLE = 1;
+ localparam CLK_REG = 2;
+ localparam CLK_INV = 3;
+ localparam POST_IDLE = 4;
+ localparam IDLE_SEN = 5;
+
+ reg [2:0] state;
+
+ reg ready_reg;
+ assign ready = ready_reg && ~trigger_spi;
+
+ //serial clock either idles or is in one of two clock states
+ reg sclk_reg;
+ assign sclk = sclk_reg;
+
+ //serial enables either idle or enabled based on state
+ wire sen_is_idle = (state == WAIT_TRIG) || (state == IDLE_SEN);
+ wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
+ reg [WIDTH-1:0] sen_reg;
+ always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
+ assign sen = sen_reg;
+
+ //data output shift register
+ reg [31:0] dataout_reg;
+ wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
+ assign mosi = dataout_reg[31];
+
+ //data input shift register
+ reg [31:0] datain_reg;
+ wire [31:0] datain_next = {datain_reg[30:0], miso};
+ assign readback = datain_reg;
+
+ //counter for spi clock
+ reg [15:0] sclk_counter;
+ wire sclk_counter_done = (sclk_counter == sclk_divider);
+ wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1;
+
+ //counter for latching bits miso/mosi
+ reg [6:0] bit_counter;
+ wire [6:0] bit_counter_next = bit_counter + 1;
+ wire bit_counter_done = (bit_counter_next == num_bits);
+
+ always @(posedge clock) begin
+ if (reset) begin
+ state <= WAIT_TRIG;
+ sclk_reg <= CLK_IDLE;
+ ready_reg <= 0;
+ end
+ else begin
+ case (state)
+
+ WAIT_TRIG: begin
+ if (trigger_spi) state <= PRE_IDLE;
+ ready_reg <= ~trigger_spi;
+ dataout_reg <= mosi_data;
+ sclk_counter <= 0;
+ bit_counter <= 0;
+ sclk_reg <= CLK_IDLE;
+ end
+
+ PRE_IDLE: begin
+ if (sclk_counter_done) state <= CLK_REG;
+ sclk_counter <= sclk_counter_next;
+ sclk_reg <= CLK_IDLE;
+ end
+
+ CLK_REG: begin
+ if (sclk_counter_done) begin
+ state <= CLK_INV;
+ if (datain_edge != CLK_IDLE) datain_reg <= datain_next;
+ if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next;
+ sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0
+ end
+ sclk_counter <= sclk_counter_next;
+ end
+
+ CLK_INV: begin
+ if (sclk_counter_done) begin
+ state <= (bit_counter_done)? POST_IDLE : CLK_REG;
+ bit_counter <= bit_counter_next;
+ if (datain_edge == CLK_IDLE) datain_reg <= datain_next;
+ if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next;
+ sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0
+ end
+ sclk_counter <= sclk_counter_next;
+ end
+
+ POST_IDLE: begin
+ if (sclk_counter_done) state <= IDLE_SEN;
+ sclk_counter <= sclk_counter_next;
+ sclk_reg <= CLK_IDLE;
+ end
+
+ IDLE_SEN: begin
+ if (sclk_counter_done) state <= WAIT_TRIG;
+ sclk_counter <= sclk_counter_next;
+ sclk_reg <= CLK_IDLE;
+ end
+
+ default: state <= WAIT_TRIG;
+
+ endcase //state
+ end
+ end
+
+ assign debug = {
+ trigger_spi, state, //4
+ sclk, mosi, miso, ready, //4
+ sen[7:0], //8
+ 1'b0, bit_counter[6:0], //8
+ sclk_counter_done, bit_counter_done, //2
+ sclk_counter[5:0] //6
+ };
+
+endmodule //simple_spi_core
diff --git a/fpga/usrp2/control_lib/simple_uart.v b/fpga/usrp2/control_lib/simple_uart.v
new file mode 100644
index 000000000..f44a719f4
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart.v
@@ -0,0 +1,79 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module simple_uart
+ #(parameter TXDEPTH = 1,
+ parameter RXDEPTH = 1,
+ parameter CLKDIV_DEFAULT = 16'd0)
+ (input clk_i, input rst_i,
+ input we_i, input stb_i, input cyc_i, output reg ack_o,
+ input [2:0] adr_i, input [31:0] dat_i, output reg [31:0] dat_o,
+ output rx_int_o, output tx_int_o, output tx_o, input rx_i, output baud_o);
+
+ // Register Map
+ localparam SUART_CLKDIV = 0;
+ localparam SUART_TXLEVEL = 1;
+ localparam SUART_RXLEVEL = 2;
+ localparam SUART_TXCHAR = 3;
+ localparam SUART_RXCHAR = 4;
+
+ wire wb_acc = cyc_i & stb_i; // WISHBONE access
+ wire wb_wr = wb_acc & we_i; // WISHBONE write access
+
+ reg [15:0] clkdiv;
+ wire [7:0] rx_char;
+ wire tx_fifo_full, rx_fifo_empty;
+ wire [7:0] tx_fifo_level, rx_fifo_level;
+
+ always @(posedge clk_i)
+ if (rst_i)
+ ack_o <= 1'b0;
+ else
+ ack_o <= wb_acc & ~ack_o;
+
+ always @(posedge clk_i)
+ if (rst_i)
+ clkdiv <= CLKDIV_DEFAULT;
+ else if (wb_wr)
+ case(adr_i)
+ SUART_CLKDIV : clkdiv <= dat_i[15:0];
+ endcase // case(adr_i)
+
+ always @(posedge clk_i)
+ case (adr_i)
+ SUART_TXLEVEL : dat_o <= tx_fifo_level;
+ SUART_RXLEVEL : dat_o <= rx_fifo_level;
+ SUART_RXCHAR : dat_o <= rx_char;
+ endcase // case(adr_i)
+
+ simple_uart_tx #(.DEPTH(TXDEPTH)) simple_uart_tx
+ (.clk(clk_i),.rst(rst_i),
+ .fifo_in(dat_i[7:0]),.fifo_write(ack_o && wb_wr && (adr_i == SUART_TXCHAR)),
+ .fifo_level(tx_fifo_level),.fifo_full(tx_fifo_full),
+ .clkdiv(clkdiv),.baudclk(baud_o),.tx(tx_o));
+
+ simple_uart_rx #(.DEPTH(RXDEPTH)) simple_uart_rx
+ (.clk(clk_i),.rst(rst_i),
+ .fifo_out(rx_char),.fifo_read(ack_o && ~wb_wr && (adr_i == SUART_RXCHAR)),
+ .fifo_level(rx_fifo_level),.fifo_empty(rx_fifo_empty),
+ .clkdiv(clkdiv),.rx(rx_i));
+
+ assign tx_int_o = ~tx_fifo_full;
+ assign rx_int_o = ~rx_fifo_empty;
+
+endmodule // simple_uart
diff --git a/fpga/usrp2/control_lib/simple_uart_rx.v b/fpga/usrp2/control_lib/simple_uart_rx.v
new file mode 100644
index 000000000..5f7646e03
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart_rx.v
@@ -0,0 +1,81 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module simple_uart_rx
+ #(parameter DEPTH=0)
+ (input clk, input rst,
+ output [7:0] fifo_out, input fifo_read, output [7:0] fifo_level, output fifo_empty,
+ input [15:0] clkdiv, input rx);
+
+ reg rx_d1, rx_d2;
+ always @(posedge clk)
+ if(rst)
+ {rx_d2,rx_d1} <= 0;
+ else
+ {rx_d2,rx_d1} <= {rx_d1,rx};
+
+ reg [15:0] baud_ctr;
+ reg [3:0] bit_ctr;
+ reg [7:0] sr;
+
+ wire neg_trans = rx_d2 & ~rx_d1;
+ wire shift_now = baud_ctr == (clkdiv>>1);
+ wire stop_now = (bit_ctr == 10) && shift_now;
+ wire go_now = (bit_ctr == 0) && neg_trans;
+
+ always @(posedge clk)
+ if(rst)
+ sr <= 0;
+ else if(shift_now)
+ sr <= {rx_d2,sr[7:1]};
+
+ always @(posedge clk)
+ if(rst)
+ baud_ctr <= 0;
+ else
+ if(go_now)
+ baud_ctr <= 1;
+ else if(stop_now)
+ baud_ctr <= 0;
+ else if(baud_ctr >= clkdiv)
+ baud_ctr <= 1;
+ else if(baud_ctr != 0)
+ baud_ctr <= baud_ctr + 1;
+
+ always @(posedge clk)
+ if(rst)
+ bit_ctr <= 0;
+ else
+ if(go_now)
+ bit_ctr <= 1;
+ else if(stop_now)
+ bit_ctr <= 0;
+ else if(baud_ctr == clkdiv)
+ bit_ctr <= bit_ctr + 1;
+
+ wire full;
+ wire write = ~full & rx_d2 & stop_now;
+
+ medfifo #(.WIDTH(8),.DEPTH(DEPTH)) fifo
+ (.clk(clk),.rst(rst),
+ .datain(sr),.write(write),.full(full),
+ .dataout(fifo_out),.read(fifo_read),.empty(fifo_empty),
+ .clear(0),.space(),.occupied(fifo_level) );
+
+endmodule // simple_uart_rx
diff --git a/fpga/usrp2/control_lib/simple_uart_tx.v b/fpga/usrp2/control_lib/simple_uart_tx.v
new file mode 100644
index 000000000..f38460bd4
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart_tx.v
@@ -0,0 +1,77 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module simple_uart_tx
+ #(parameter DEPTH=0)
+ (input clk, input rst,
+ input [7:0] fifo_in, input fifo_write, output [7:0] fifo_level, output fifo_full,
+ input [15:0] clkdiv, output baudclk, output reg tx);
+
+ reg [15:0] baud_ctr;
+ reg [3:0] bit_ctr;
+
+ wire read, empty;
+ wire [7:0] char_to_send;
+
+ medfifo #(.WIDTH(8),.DEPTH(DEPTH)) fifo
+ (.clk(clk),.rst(rst),
+ .datain(fifo_in),.write(fifo_write),.full(fifo_full),
+ .dataout(char_to_send),.read(read),.empty(empty),
+ .clear(0),.space(fifo_level),.occupied() );
+
+ always @(posedge clk)
+ if(rst)
+ baud_ctr <= 0;
+ else if (baud_ctr >= clkdiv)
+ baud_ctr <= 0;
+ else
+ baud_ctr <= baud_ctr + 1;
+
+ always @(posedge clk)
+ if(rst)
+ bit_ctr <= 0;
+ else if(baud_ctr == clkdiv)
+ if(bit_ctr == 9)
+ bit_ctr <= 0;
+ else if(bit_ctr != 0)
+ bit_ctr <= bit_ctr + 1;
+ else if(~empty)
+ bit_ctr <= 1;
+
+ always @(posedge clk)
+ if(rst)
+ tx <= 1;
+ else
+ case(bit_ctr)
+ 0 : tx <= 1;
+ 1 : tx <= 0;
+ 2 : tx <= char_to_send[0];
+ 3 : tx <= char_to_send[1];
+ 4 : tx <= char_to_send[2];
+ 5 : tx <= char_to_send[3];
+ 6 : tx <= char_to_send[4];
+ 7 : tx <= char_to_send[5];
+ 8 : tx <= char_to_send[6];
+ 9 : tx <= char_to_send[7];
+ default : tx <= 1;
+ endcase // case(bit_ctr)
+
+ assign read = (bit_ctr == 9) && (baud_ctr == clkdiv);
+ assign baudclk = (baud_ctr == 1); // Only for debug purposes
+
+endmodule // simple_uart_tx
diff --git a/fpga/usrp2/control_lib/spi.v b/fpga/usrp2/control_lib/spi.v
new file mode 100644
index 000000000..1abebee1c
--- /dev/null
+++ b/fpga/usrp2/control_lib/spi.v
@@ -0,0 +1,101 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// AD9510 Register Map (from datasheet Rev. A)
+
+/* INSTRUCTION word format (16 bits)
+ * 15 Read = 1, Write = 0
+ * 14:13 W1/W0, Number of bytes 00 - 1, 01 - 2, 10 - 3, 11 - stream
+ * 12:0 Address
+ */
+
+/* ADDR Contents Value (hex)
+ * 00 Serial Config Port 10 (def) -- MSB first, SDI/SDO separate
+ * 04 A Counter
+ * 05-06 B Counter
+ * 07-0A PLL Control
+ * 0B-0C R Divider
+ * 0D PLL Control
+ * 34-3A Fine Delay
+ * 3C-3F LVPECL Outs
+ * 40-43 LVDS/CMOS Outs
+ * 45 Clock select, power down
+ * 48-57 Dividers
+ * 58 Func and Sync
+ * 5A Update regs
+ */
+
+
+module spi
+ (input reset,
+ input clk,
+
+ // SPI signals
+ output sen,
+ output sclk,
+ input sdi,
+ output sdo,
+
+ // Interfaces
+ input read_1,
+ input write_1,
+ input [15:0] command_1,
+ input [15:0] wdata_1,
+ output [15:0] rdata_1,
+ output reg done_1,
+ input msb_first_1,
+ input [5:0] command_width_1,
+ input [5:0] data_width_1,
+ input [7:0] clkdiv_1
+
+ );
+
+ reg [15:0] command, wdata, rdata;
+ reg done;
+
+ always @(posedge clk)
+ if(reset)
+ done_1 <= #1 1'b0;
+
+ always @(posedge clk)
+ if(reset)
+ begin
+ counter <= #1 7'd0;
+ command <= #1 20'd0;
+ end
+ else if(start)
+ begin
+ counter <= #1 7'd1;
+ command <= #1 {read,w,addr_data};
+ end
+ else if( |counter && ~done )
+ begin
+ counter <= #1 counter + 7'd1;
+ if(~counter[0])
+ command <= {command[22:0],1'b0};
+ end
+
+ wire done = (counter == 8'd49);
+
+ assign sen = (done | counter == 8'd0); // CSB is high when we're not doing anything
+ assign sclk = ~counter[0];
+ assign sdo = command[23];
+
+
+endmodule // clock_control
diff --git a/fpga/usrp2/control_lib/srl.v b/fpga/usrp2/control_lib/srl.v
new file mode 100644
index 000000000..bdef30058
--- /dev/null
+++ b/fpga/usrp2/control_lib/srl.v
@@ -0,0 +1,38 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module srl
+ #(parameter WIDTH=18)
+ (input clk,
+ input write,
+ input [WIDTH-1:0] in,
+ input [3:0] addr,
+ output [WIDTH-1:0] out);
+
+ genvar i;
+ generate
+ for (i=0;i<WIDTH;i=i+1)
+ begin : gen_srl
+ SRL16E
+ srl16e(.Q(out[i]),
+ .A0(addr[0]),.A1(addr[1]),.A2(addr[2]),.A3(addr[3]),
+ .CE(write),.CLK(clk),.D(in[i]));
+ end
+ endgenerate
+
+endmodule // srl
diff --git a/fpga/usrp2/control_lib/ss_rcvr.v b/fpga/usrp2/control_lib/ss_rcvr.v
new file mode 100644
index 000000000..4fb732c23
--- /dev/null
+++ b/fpga/usrp2/control_lib/ss_rcvr.v
@@ -0,0 +1,98 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Source-synchronous receiver
+// Assumes both clocks are at the same rate
+// Relative clock phase is
+// unknown
+// variable
+// bounded
+// The output will come several cycles later than the input
+
+// This should synthesize efficiently in Xilinx distributed ram cells,
+// which is why we use a buffer depth of 16
+
+// FIXME Async reset on rxclk side?
+
+module ss_rcvr
+ #(parameter WIDTH=16)
+ (input rxclk,
+ input sysclk,
+ input rst,
+
+ input [WIDTH-1:0] data_in,
+ output [WIDTH-1:0] data_out,
+ output reg clock_present);
+
+ wire [3:0] rd_addr, wr_addr;
+
+ // Distributed RAM
+ reg [WIDTH-1:0] buffer [0:15];
+ always @(posedge rxclk)
+ buffer[wr_addr] <= data_in;
+
+ assign data_out = buffer[rd_addr];
+
+ // Write address generation
+ reg [3:0] wr_counter;
+ always @(posedge rxclk or posedge rst)
+ if (rst)
+ wr_counter <= 0;
+ else
+ wr_counter <= wr_counter + 1;
+
+ assign wr_addr = {wr_counter[3], ^wr_counter[3:2], ^wr_counter[2:1], ^wr_counter[1:0]};
+
+ // Read Address generation
+ wire [3:0] wr_ctr_sys, diff, abs_diff;
+ reg [3:0] wr_addr_sys_d1, wr_addr_sys_d2;
+ reg [3:0] rd_counter;
+
+ assign rd_addr = {rd_counter[3], ^rd_counter[3:2], ^rd_counter[2:1], ^rd_counter[1:0]};
+
+ always @(posedge sysclk)
+ wr_addr_sys_d1 <= wr_addr;
+
+ always @(posedge sysclk)
+ wr_addr_sys_d2 <= wr_addr_sys_d1;
+
+ assign wr_ctr_sys = {wr_addr_sys_d2[3],^wr_addr_sys_d2[3:2],^wr_addr_sys_d2[3:1],^wr_addr_sys_d2[3:0]};
+
+ assign diff = wr_ctr_sys - rd_counter;
+ assign abs_diff = diff[3] ? (~diff+1) : diff;
+
+ always @(posedge sysclk)
+ if(rst)
+ begin
+ clock_present <= 0;
+ rd_counter <= 0;
+ end
+ else
+ if(~clock_present)
+ if(abs_diff > 5)
+ clock_present <= 1;
+ else
+ ;
+ else
+ if(abs_diff<3)
+ clock_present <= 0;
+ else
+ rd_counter <= rd_counter + 1;
+
+endmodule // ss_rcvr
diff --git a/fpga/usrp2/control_lib/system_control.v b/fpga/usrp2/control_lib/system_control.v
new file mode 100644
index 000000000..7e7b71f3c
--- /dev/null
+++ b/fpga/usrp2/control_lib/system_control.v
@@ -0,0 +1,64 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// System bootup order:
+// 0 - Internal POR to reset this block. Maybe control it from CPLD in the future?
+// 1 - Everything in reset
+// 2 - Take RAM Loader out of reset
+// 3 - When RAM Loader done, take processor and wishbone out of reset
+
+module system_control
+ (input wb_clk_i,
+ output reg ram_loader_rst_o,
+ output reg wb_rst_o,
+ input ram_loader_done_i
+ );
+
+ reg POR = 1'b1;
+ reg [3:0] POR_ctr;
+
+ initial POR_ctr = 4'd0;
+ always @(posedge wb_clk_i)
+ if(POR_ctr == 4'd15)
+ POR <= 1'b0;
+ else
+ POR_ctr <= POR_ctr + 4'd1;
+
+ always @(posedge POR or posedge wb_clk_i)
+ if(POR)
+ ram_loader_rst_o <= 1'b1;
+ else
+ ram_loader_rst_o <= #1 1'b0;
+
+ // Main system reset
+ reg delayed_rst;
+
+ always @(posedge POR or posedge wb_clk_i)
+ if(POR)
+ begin
+ wb_rst_o <= 1'b1;
+ delayed_rst <= 1'b1;
+ end
+ else if(ram_loader_done_i)
+ begin
+ delayed_rst <= 1'b0;
+ wb_rst_o <= delayed_rst;
+ end
+
+endmodule // system_control
+
+
diff --git a/fpga/usrp2/control_lib/system_control_tb.v b/fpga/usrp2/control_lib/system_control_tb.v
new file mode 100644
index 000000000..8fecfd1f0
--- /dev/null
+++ b/fpga/usrp2/control_lib/system_control_tb.v
@@ -0,0 +1,74 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module system_control_tb();
+
+ reg aux_clk, clk_fpga;
+ wire wb_clk, dsp_clk;
+ wire wb_rst, dsp_rst, rl_rst, proc_rst;
+
+ reg rl_done, clock_ready;
+
+ initial aux_clk = 1'b0;
+ always #25 aux_clk = ~aux_clk;
+
+ initial clk_fpga = 1'b0;
+
+ initial clock_ready = 1'b0;
+ initial
+ begin
+ @(negedge proc_rst);
+ #1003 clock_ready <= 1'b1;
+ end
+
+ always #7 clk_fpga = ~clk_fpga;
+
+ initial begin
+ $dumpfile("system_control_tb.vcd");
+ $dumpvars(0,system_control_tb);
+ end
+
+ initial #10000 $finish;
+
+ initial
+ begin
+ @(negedge rl_rst);
+ rl_done <= 1'b0;
+ #1325 rl_done <= 1'b1;
+ end
+
+ initial
+ begin
+ @(negedge proc_rst);
+ clock_ready <= 1'b0;
+ #327 clock_ready <= 1'b1;
+ end
+
+ system_control
+ system_control(.aux_clk_i(aux_clk),.clk_fpga_i(clk_fpga),
+ .dsp_clk_o(dsp_clk),.wb_clk_o(wb_clk),
+ .ram_loader_rst_o(rl_rst),
+ .processor_rst_o(proc_rst),
+ .wb_rst_o(wb_rst),
+ .dsp_rst_o(dsp_rst),
+ .ram_loader_done_i(rl_done),
+ .clock_ready_i(clock_ready),
+ .debug_o());
+
+endmodule // system_control_tb
diff --git a/fpga/usrp2/control_lib/traffic_cop.v b/fpga/usrp2/control_lib/traffic_cop.v
new file mode 100644
index 000000000..874e4c2d9
--- /dev/null
+++ b/fpga/usrp2/control_lib/traffic_cop.v
@@ -0,0 +1,42 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module traffic_cop();
+
+
+endmodule // traffic_cop
+
+
+
+/*
+
+ Traffic Cop to control buffer pool
+
+ Inputs
+
+ Commands
+
+ Basic Operations
+
+ Outputs
+
+
+
+
+
+ */
diff --git a/fpga/usrp2/control_lib/user_settings.v b/fpga/usrp2/control_lib/user_settings.v
new file mode 100644
index 000000000..d87f1de21
--- /dev/null
+++ b/fpga/usrp2/control_lib/user_settings.v
@@ -0,0 +1,63 @@
+//
+// Copyright 2012 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+// User settings bus
+//
+// Provides 8-bit address, 32-bit data write only bus for user settings, consumes to addresses in
+// normal settings bus.
+//
+// Write user address to BASE
+// Write user data to BASE+1
+//
+// The user_set_stb will strobe after data write, must write new address even if same as previous one.
+
+module user_settings
+ #(parameter BASE=0)
+ (input clk,
+ input rst,
+
+ input set_stb,
+ input [7:0] set_addr,
+ input [31:0] set_data,
+
+ output set_stb_user,
+ output [7:0] set_addr_user,
+ output [31:0] set_data_user
+ );
+
+ wire addr_changed, data_changed;
+ reg stb_int;
+
+ setting_reg #(.my_addr(BASE+0),.width(8)) sr_0
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(set_addr_user),.changed(addr_changed) );
+
+ setting_reg #(.my_addr(BASE+1)) sr_1
+ (.clk(clk),.rst(rst),.strobe(set_stb),.addr(set_addr),
+ .in(set_data),.out(set_data_user),.changed(data_changed) );
+
+ always @(posedge clk)
+ if (rst|set_stb_user)
+ stb_int <= 0;
+ else
+ if (addr_changed)
+ stb_int <= 1;
+
+ assign set_stb_user = stb_int & data_changed;
+
+endmodule // user_settings
+
diff --git a/fpga/usrp2/control_lib/v5icap_wb.v b/fpga/usrp2/control_lib/v5icap_wb.v
new file mode 100644
index 000000000..92a6769e5
--- /dev/null
+++ b/fpga/usrp2/control_lib/v5icap_wb.v
@@ -0,0 +1,71 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module v5icap_wb
+ (input clk, input reset,
+ input cyc_i, input stb_i, input we_i, output ack_o,
+ input [31:0] dat_i, output [31:0] dat_o);
+
+ wire BUSY, CE, WRITE;
+
+ reg [2:0] icap_state;
+ localparam ICAP_IDLE = 0;
+ localparam ICAP_WR0 = 1;
+ localparam ICAP_WR1 = 2;
+ localparam ICAP_RD0 = 3;
+ localparam ICAP_RD1 = 4;
+
+ always @(posedge clk)
+ if(reset)
+ icap_state <= ICAP_IDLE;
+ else
+ case(icap_state)
+ ICAP_IDLE :
+ begin
+ if(stb_i & cyc_i)
+ if(we_i)
+ icap_state <= ICAP_WR0;
+ else
+ icap_state <= ICAP_RD0;
+ end
+ ICAP_WR0 :
+ icap_state <= ICAP_WR1;
+ ICAP_WR1 :
+ icap_state <= ICAP_IDLE;
+ ICAP_RD0 :
+ icap_state <= ICAP_RD1;
+ ICAP_RD1 :
+ icap_state <= ICAP_IDLE;
+ endcase // case (icap_state)
+
+ assign WRITE = (icap_state == ICAP_WR0) | (icap_state == ICAP_WR1);
+ assign CE = (icap_state == ICAP_WR1) | (icap_state == ICAP_RD0);
+
+ assign ack_o = (icap_state == ICAP_WR1) | (icap_state == ICAP_RD1);
+
+ ICAP_VIRTEX5 #(.ICAP_WIDTH("X32")) ICAP_VIRTEX5_inst
+ (.BUSY(BUSY), // Busy output
+ .O(dat_o), // 32-bit data output
+ .CE(~CE), // Clock enable input
+ .CLK(clk), // Clock input
+ .I(dat_i), // 32-bit data input
+ .WRITE(~WRITE) // Write input
+ );
+
+endmodule // v5icap_wb
diff --git a/fpga/usrp2/control_lib/wb_1master.v b/fpga/usrp2/control_lib/wb_1master.v
new file mode 100644
index 000000000..fb313efae
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_1master.v
@@ -0,0 +1,464 @@
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// WISHBONE Connection Bus Top Level ////
+//// ////
+//// ////
+//// Original Author: Johny Chi ////
+//// chisuhua@yahoo.com.cn ////
+//// Modified By Matt Ettus, matt@ettus.com ////
+//// ////
+//// ////
+/////////////////////////////////////////////////////////////////////
+//// ////
+//// Copyright (C) 2000, 2007 Authors and OPENCORES.ORG ////
+//// ////
+//// This source file may be used and distributed without ////
+//// restriction provided that this copyright statement is not ////
+//// removed from the file and that any derivative work contains ////
+//// the original copyright notice and the associated disclaimer. ////
+//// ////
+//// This source file is free software; you can redistribute it ////
+//// and/or modify it under the terms of the GNU Lesser General ////
+//// Public License as published by the Free Software Foundation; ////
+//// either version 2.1 of the License, or (at your option) any ////
+//// later version. ////
+//// ////
+//// This source 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 Lesser General Public License for more ////
+//// details. ////
+//// ////
+//// You should have received a copy of the GNU Lesser General ////
+//// Public License along with this source; if not, download it ////
+//// from http://www.opencores.org/lgpl.shtml ////
+//// ////
+//////////////////////////////////////////////////////////////////////
+//
+// Up to 8 slaves share a Wishbone Bus connection to 1 master
+
+ module wb_1master
+ #(parameter decode_w = 8, // address decode width
+ parameter s0_addr = 8'h0, // slave 0 address
+ parameter s0_mask = 8'h0, // slave 0 don't cares
+ parameter s1_addr = 8'h0, // slave 1 address
+ parameter s1_mask = 8'h0, // slave 1 don't cares
+ parameter s2_addr = 8'h0, // slave 2 address
+ parameter s2_mask = 8'h0, // slave 2 don't cares
+ parameter s3_addr = 8'h0, // slave 3 address
+ parameter s3_mask = 8'h0, // slave 3 don't cares
+ parameter s4_addr = 8'h0, // slave 4 address
+ parameter s4_mask = 8'h0, // slave 4 don't cares
+ parameter s5_addr = 8'h0, // slave 5 address
+ parameter s5_mask = 8'h0, // slave 5 don't cares
+ parameter s6_addr = 8'h0, // slave 6 address
+ parameter s6_mask = 8'h0, // slave 6 don't cares
+ parameter s7_addr = 8'h0, // slave 7 address
+ parameter s7_mask = 8'h0, // slave 7 don't cares
+ parameter s8_addr = 8'h0, // slave 8 address
+ parameter s8_mask = 8'h0, // slave 8 don't cares
+ parameter s9_addr = 8'h0, // slave 9 address
+ parameter s9_mask = 8'h0, // slave 9 don't cares
+ parameter sa_addr = 8'h0, // slave a address
+ parameter sa_mask = 8'h0, // slave a don't cares
+ parameter sb_addr = 8'h0, // slave b address
+ parameter sb_mask = 8'h0, // slave b don't cares
+ parameter sc_addr = 8'h0, // slave c address
+ parameter sc_mask = 8'h0, // slave c don't cares
+ parameter sd_addr = 8'h0, // slave d address
+ parameter sd_mask = 8'h0, // slave d don't cares
+ parameter se_addr = 8'h0, // slave e address
+ parameter se_mask = 8'h0, // slave e don't cares
+ parameter sf_addr = 8'h0, // slave f address
+ parameter sf_mask = 8'h0, // slave f don't cares
+
+ parameter dw = 32, // Data bus Width
+ parameter aw = 32, // Address bus Width
+ parameter sw = 4) // Number of Select Lines
+
+ (input clk_i,
+ input rst_i,
+
+ // Master Interface
+ input [dw-1:0] m0_dat_i,
+ output [dw-1:0] m0_dat_o,
+ input [aw-1:0] m0_adr_i,
+ input [sw-1:0] m0_sel_i,
+ input m0_we_i,
+ input m0_cyc_i,
+ input m0_stb_i,
+ output m0_ack_o,
+ output m0_err_o,
+ output m0_rty_o,
+
+ // Slave Interfaces
+ input [dw-1:0] s0_dat_i,
+ output [dw-1:0] s0_dat_o,
+ output [aw-1:0] s0_adr_o,
+ output [sw-1:0] s0_sel_o,
+ output s0_we_o,
+ output s0_cyc_o,
+ output s0_stb_o,
+ input s0_ack_i,
+ input s0_err_i,
+ input s0_rty_i,
+
+ input [dw-1:0] s1_dat_i,
+ output [dw-1:0] s1_dat_o,
+ output [aw-1:0] s1_adr_o,
+ output [sw-1:0] s1_sel_o,
+ output s1_we_o,
+ output s1_cyc_o,
+ output s1_stb_o,
+ input s1_ack_i,
+ input s1_err_i,
+ input s1_rty_i,
+
+ input [dw-1:0] s2_dat_i,
+ output [dw-1:0] s2_dat_o,
+ output [aw-1:0] s2_adr_o,
+ output [sw-1:0] s2_sel_o,
+ output s2_we_o,
+ output s2_cyc_o,
+ output s2_stb_o,
+ input s2_ack_i,
+ input s2_err_i,
+ input s2_rty_i,
+
+ input [dw-1:0] s3_dat_i,
+ output [dw-1:0] s3_dat_o,
+ output [aw-1:0] s3_adr_o,
+ output [sw-1:0] s3_sel_o,
+ output s3_we_o,
+ output s3_cyc_o,
+ output s3_stb_o,
+ input s3_ack_i,
+ input s3_err_i,
+ input s3_rty_i,
+
+ input [dw-1:0] s4_dat_i,
+ output [dw-1:0] s4_dat_o,
+ output [aw-1:0] s4_adr_o,
+ output [sw-1:0] s4_sel_o,
+ output s4_we_o,
+ output s4_cyc_o,
+ output s4_stb_o,
+ input s4_ack_i,
+ input s4_err_i,
+ input s4_rty_i,
+
+ input [dw-1:0] s5_dat_i,
+ output [dw-1:0] s5_dat_o,
+ output [aw-1:0] s5_adr_o,
+ output [sw-1:0] s5_sel_o,
+ output s5_we_o,
+ output s5_cyc_o,
+ output s5_stb_o,
+ input s5_ack_i,
+ input s5_err_i,
+ input s5_rty_i,
+
+ input [dw-1:0] s6_dat_i,
+ output [dw-1:0] s6_dat_o,
+ output [aw-1:0] s6_adr_o,
+ output [sw-1:0] s6_sel_o,
+ output s6_we_o,
+ output s6_cyc_o,
+ output s6_stb_o,
+ input s6_ack_i,
+ input s6_err_i,
+ input s6_rty_i,
+
+ input [dw-1:0] s7_dat_i,
+ output [dw-1:0] s7_dat_o,
+ output [aw-1:0] s7_adr_o,
+ output [sw-1:0] s7_sel_o,
+ output s7_we_o,
+ output s7_cyc_o,
+ output s7_stb_o,
+ input s7_ack_i,
+ input s7_err_i,
+ input s7_rty_i,
+
+ input [dw-1:0] s8_dat_i,
+ output [dw-1:0] s8_dat_o,
+ output [aw-1:0] s8_adr_o,
+ output [sw-1:0] s8_sel_o,
+ output s8_we_o,
+ output s8_cyc_o,
+ output s8_stb_o,
+ input s8_ack_i,
+ input s8_err_i,
+ input s8_rty_i,
+
+ input [dw-1:0] s9_dat_i,
+ output [dw-1:0] s9_dat_o,
+ output [aw-1:0] s9_adr_o,
+ output [sw-1:0] s9_sel_o,
+ output s9_we_o,
+ output s9_cyc_o,
+ output s9_stb_o,
+ input s9_ack_i,
+ input s9_err_i,
+ input s9_rty_i,
+
+ input [dw-1:0] sa_dat_i,
+ output [dw-1:0] sa_dat_o,
+ output [aw-1:0] sa_adr_o,
+ output [sw-1:0] sa_sel_o,
+ output sa_we_o,
+ output sa_cyc_o,
+ output sa_stb_o,
+ input sa_ack_i,
+ input sa_err_i,
+ input sa_rty_i,
+
+ input [dw-1:0] sb_dat_i,
+ output [dw-1:0] sb_dat_o,
+ output [aw-1:0] sb_adr_o,
+ output [sw-1:0] sb_sel_o,
+ output sb_we_o,
+ output sb_cyc_o,
+ output sb_stb_o,
+ input sb_ack_i,
+ input sb_err_i,
+ input sb_rty_i,
+
+ input [dw-1:0] sc_dat_i,
+ output [dw-1:0] sc_dat_o,
+ output [aw-1:0] sc_adr_o,
+ output [sw-1:0] sc_sel_o,
+ output sc_we_o,
+ output sc_cyc_o,
+ output sc_stb_o,
+ input sc_ack_i,
+ input sc_err_i,
+ input sc_rty_i,
+
+ input [dw-1:0] sd_dat_i,
+ output [dw-1:0] sd_dat_o,
+ output [aw-1:0] sd_adr_o,
+ output [sw-1:0] sd_sel_o,
+ output sd_we_o,
+ output sd_cyc_o,
+ output sd_stb_o,
+ input sd_ack_i,
+ input sd_err_i,
+ input sd_rty_i,
+
+ input [dw-1:0] se_dat_i,
+ output [dw-1:0] se_dat_o,
+ output [aw-1:0] se_adr_o,
+ output [sw-1:0] se_sel_o,
+ output se_we_o,
+ output se_cyc_o,
+ output se_stb_o,
+ input se_ack_i,
+ input se_err_i,
+ input se_rty_i,
+
+ input [dw-1:0] sf_dat_i,
+ output [dw-1:0] sf_dat_o,
+ output [aw-1:0] sf_adr_o,
+ output [sw-1:0] sf_sel_o,
+ output sf_we_o,
+ output sf_cyc_o,
+ output sf_stb_o,
+ input sf_ack_i,
+ input sf_err_i,
+ input sf_rty_i
+ );
+
+ // ////////////////////////////////////////////////////////////////
+ //
+ // Local wires
+ //
+
+ wire [15:0] ssel_dec;
+ reg [dw-1:0] i_dat_s; // internal share bus , slave data to master
+
+ // Master output Interface
+ assign m0_dat_o = i_dat_s;
+
+ always @*
+ case(ssel_dec)
+ 1 : i_dat_s <= s0_dat_i;
+ 2 : i_dat_s <= s1_dat_i;
+ 4 : i_dat_s <= s2_dat_i;
+ 8 : i_dat_s <= s3_dat_i;
+ 16 : i_dat_s <= s4_dat_i;
+ 32 : i_dat_s <= s5_dat_i;
+ 64 : i_dat_s <= s6_dat_i;
+ 128 : i_dat_s <= s7_dat_i;
+ 256 : i_dat_s <= s8_dat_i;
+ 512 : i_dat_s <= s9_dat_i;
+ 1024 : i_dat_s <= sa_dat_i;
+ 2048 : i_dat_s <= sb_dat_i;
+ 4096 : i_dat_s <= sc_dat_i;
+ 8192 : i_dat_s <= sd_dat_i;
+ 16384 : i_dat_s <= se_dat_i;
+ 32768 : i_dat_s <= sf_dat_i;
+ default : i_dat_s <= s0_dat_i;
+ endcase // case(ssel_dec)
+
+ assign {m0_ack_o, m0_err_o, m0_rty_o}
+ = {s0_ack_i | s1_ack_i | s2_ack_i | s3_ack_i | s4_ack_i | s5_ack_i | s6_ack_i | s7_ack_i |
+ s8_ack_i | s9_ack_i | sa_ack_i | sb_ack_i | sc_ack_i | sd_ack_i | se_ack_i | sf_ack_i ,
+ s0_err_i | s1_err_i | s2_err_i | s3_err_i | s4_err_i | s5_err_i | s6_err_i | s7_err_i |
+ s8_err_i | s9_err_i | sa_err_i | sb_err_i | sc_err_i | sd_err_i | se_err_i | sf_err_i ,
+ s0_rty_i | s1_rty_i | s2_rty_i | s3_rty_i | s4_rty_i | s5_rty_i | s6_rty_i | s7_rty_i |
+ s8_rty_i | s9_rty_i | sa_rty_i | sb_rty_i | sc_rty_i | sd_rty_i | se_rty_i | sf_rty_i };
+
+ // Slave output interfaces
+ assign s0_adr_o = m0_adr_i;
+ assign s0_sel_o = m0_sel_i;
+ assign s0_dat_o = m0_dat_i;
+ assign s0_we_o = m0_we_i;
+ assign s0_cyc_o = m0_cyc_i;
+ assign s0_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[0];
+
+ assign s1_adr_o = m0_adr_i;
+ assign s1_sel_o = m0_sel_i;
+ assign s1_dat_o = m0_dat_i;
+ assign s1_we_o = m0_we_i;
+ assign s1_cyc_o = m0_cyc_i;
+ assign s1_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[1];
+
+ assign s2_adr_o = m0_adr_i;
+ assign s2_sel_o = m0_sel_i;
+ assign s2_dat_o = m0_dat_i;
+ assign s2_we_o = m0_we_i;
+ assign s2_cyc_o = m0_cyc_i;
+ assign s2_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[2];
+
+ assign s3_adr_o = m0_adr_i;
+ assign s3_sel_o = m0_sel_i;
+ assign s3_dat_o = m0_dat_i;
+ assign s3_we_o = m0_we_i;
+ assign s3_cyc_o = m0_cyc_i;
+ assign s3_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[3];
+
+ assign s4_adr_o = m0_adr_i;
+ assign s4_sel_o = m0_sel_i;
+ assign s4_dat_o = m0_dat_i;
+ assign s4_we_o = m0_we_i;
+ assign s4_cyc_o = m0_cyc_i;
+ assign s4_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[4];
+
+ assign s5_adr_o = m0_adr_i;
+ assign s5_sel_o = m0_sel_i;
+ assign s5_dat_o = m0_dat_i;
+ assign s5_we_o = m0_we_i;
+ assign s5_cyc_o = m0_cyc_i;
+ assign s5_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[5];
+
+ assign s6_adr_o = m0_adr_i;
+ assign s6_sel_o = m0_sel_i;
+ assign s6_dat_o = m0_dat_i;
+ assign s6_we_o = m0_we_i;
+ assign s6_cyc_o = m0_cyc_i;
+ assign s6_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[6];
+
+ assign s7_adr_o = m0_adr_i;
+ assign s7_sel_o = m0_sel_i;
+ assign s7_dat_o = m0_dat_i;
+ assign s7_we_o = m0_we_i;
+ assign s7_cyc_o = m0_cyc_i;
+ assign s7_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[7];
+
+ assign s8_adr_o = m0_adr_i;
+ assign s8_sel_o = m0_sel_i;
+ assign s8_dat_o = m0_dat_i;
+ assign s8_we_o = m0_we_i;
+ assign s8_cyc_o = m0_cyc_i;
+ assign s8_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[8];
+
+ assign s9_adr_o = m0_adr_i;
+ assign s9_sel_o = m0_sel_i;
+ assign s9_dat_o = m0_dat_i;
+ assign s9_we_o = m0_we_i;
+ assign s9_cyc_o = m0_cyc_i;
+ assign s9_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[9];
+
+ assign sa_adr_o = m0_adr_i;
+ assign sa_sel_o = m0_sel_i;
+ assign sa_dat_o = m0_dat_i;
+ assign sa_we_o = m0_we_i;
+ assign sa_cyc_o = m0_cyc_i;
+ assign sa_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[10];
+
+ assign sb_adr_o = m0_adr_i;
+ assign sb_sel_o = m0_sel_i;
+ assign sb_dat_o = m0_dat_i;
+ assign sb_we_o = m0_we_i;
+ assign sb_cyc_o = m0_cyc_i;
+ assign sb_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[11];
+
+ assign sc_adr_o = m0_adr_i;
+ assign sc_sel_o = m0_sel_i;
+ assign sc_dat_o = m0_dat_i;
+ assign sc_we_o = m0_we_i;
+ assign sc_cyc_o = m0_cyc_i;
+ assign sc_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[12];
+
+ assign sd_adr_o = m0_adr_i;
+ assign sd_sel_o = m0_sel_i;
+ assign sd_dat_o = m0_dat_i;
+ assign sd_we_o = m0_we_i;
+ assign sd_cyc_o = m0_cyc_i;
+ assign sd_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[13];
+
+ assign se_adr_o = m0_adr_i;
+ assign se_sel_o = m0_sel_i;
+ assign se_dat_o = m0_dat_i;
+ assign se_we_o = m0_we_i;
+ assign se_cyc_o = m0_cyc_i;
+ assign se_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[14];
+
+ assign sf_adr_o = m0_adr_i;
+ assign sf_sel_o = m0_sel_i;
+ assign sf_dat_o = m0_dat_i;
+ assign sf_we_o = m0_we_i;
+ assign sf_cyc_o = m0_cyc_i;
+ assign sf_stb_o = m0_cyc_i & m0_stb_i & ssel_dec[15];
+
+ // Address decode logic
+ // WARNING -- must make sure these are mutually exclusive!
+
+
+ assign ssel_dec[0] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s0_addr) & s0_mask);
+ assign ssel_dec[1] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s1_addr) & s1_mask);
+ assign ssel_dec[2] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s2_addr) & s2_mask);
+ assign ssel_dec[3] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s3_addr) & s3_mask);
+ assign ssel_dec[4] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s4_addr) & s4_mask);
+ assign ssel_dec[5] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s5_addr) & s5_mask);
+ assign ssel_dec[6] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s6_addr) & s6_mask);
+ assign ssel_dec[7] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s7_addr) & s7_mask);
+ assign ssel_dec[8] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s8_addr) & s8_mask);
+ assign ssel_dec[9] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ s9_addr) & s9_mask);
+ assign ssel_dec[10] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ sa_addr) & sa_mask);
+ assign ssel_dec[11] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ sb_addr) & sb_mask);
+ assign ssel_dec[12] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ sc_addr) & sc_mask);
+ assign ssel_dec[13] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ sd_addr) & sd_mask);
+ assign ssel_dec[14] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ se_addr) & se_mask);
+ assign ssel_dec[15] = ~|((m0_adr_i[aw-1:aw-decode_w] ^ sf_addr) & sf_mask);
+
+/*
+ assign ssel_dec[0] = (m0_adr_i[aw -1 : aw - decode_w ] == s0_addr);
+ assign ssel_dec[1] = (m0_adr_i[aw -1 : aw - decode_w ] == s1_addr);
+ assign ssel_dec[2] = (m0_adr_i[aw -1 : aw - decode_w ] == s2_addr);
+ assign ssel_dec[3] = (m0_adr_i[aw -1 : aw - decode_w ] == s3_addr);
+ assign ssel_dec[4] = (m0_adr_i[aw -1 : aw - decode_w ] == s4_addr);
+ assign ssel_dec[5] = (m0_adr_i[aw -1 : aw - decode_w ] == s5_addr);
+ assign ssel_dec[6] = (m0_adr_i[aw -1 : aw - decode_w ] == s6_addr);
+ assign ssel_dec[7] = (m0_adr_i[aw -1 : aw - decode_w ] == s7_addr);
+ assign ssel_dec[8] = (m0_adr_i[aw -1 : aw - decode_w ] == s8_addr);
+ assign ssel_dec[9] = (m0_adr_i[aw -1 : aw - decode_w ] == s9_addr);
+ assign ssel_dec[10] = (m0_adr_i[aw -1 : aw - decode_w ] == sa_addr);
+ assign ssel_dec[11] = (m0_adr_i[aw -1 : aw - decode_w ] == sb_addr);
+ assign ssel_dec[12] = (m0_adr_i[aw -1 : aw - decode_w ] == sc_addr);
+ assign ssel_dec[13] = (m0_adr_i[aw -1 : aw - decode_w ] == sd_addr);
+ assign ssel_dec[14] = (m0_adr_i[aw -1 : aw - decode_w ] == se_addr);
+ assign ssel_dec[15] = (m0_adr_i[aw -1 : aw - decode_w ] == sf_addr);
+ */
+endmodule // wb_1master
diff --git a/fpga/usrp2/control_lib/wb_bridge_16_32.v b/fpga/usrp2/control_lib/wb_bridge_16_32.v
new file mode 100644
index 000000000..7c62c9cbd
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_bridge_16_32.v
@@ -0,0 +1,53 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module wb_bridge_16_32
+ #(parameter AWIDTH=16)
+ (input wb_clk, input wb_rst,
+ input A_cyc_i, input A_stb_i, input A_we_i, input [3:0] A_sel_i,
+ input [AWIDTH-1:0] A_adr_i, input [31:0] A_dat_i, output [31:0] A_dat_o, output A_ack_o,
+ output B_cyc_o, output B_stb_o, output B_we_o, output [1:0] B_sel_o,
+ output [AWIDTH-1:0] B_adr_o, output [15:0] B_dat_o, input [15:0] B_dat_i, input B_ack_i
+ );
+
+ reg [15:0] holding;
+ reg phase;
+
+ assign B_adr_o = {A_adr_i[AWIDTH-1:2],phase,1'b0};
+ assign B_cyc_o = A_cyc_i;
+ assign B_stb_o = A_stb_i;
+ assign B_we_o = A_we_i;
+
+ assign B_dat_o = ~phase ? A_dat_i[15:0] : A_dat_i[31:16];
+ assign B_sel_o = ~phase ? A_sel_i[1:0] : A_sel_i[3:2];
+
+ assign A_dat_o = {B_dat_i,holding};
+ assign A_ack_o = phase & B_ack_i;
+
+ always @(posedge wb_clk)
+ if(wb_rst)
+ phase <= 0;
+ else if(B_ack_i)
+ phase <= ~phase;
+
+ always @(posedge wb_clk)
+ if(~phase & B_ack_i)
+ holding <= B_dat_i;
+
+endmodule // wb_bridge_16_32
diff --git a/fpga/usrp2/control_lib/wb_bus_writer.v b/fpga/usrp2/control_lib/wb_bus_writer.v
new file mode 100644
index 000000000..08e641d37
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_bus_writer.v
@@ -0,0 +1,74 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// wb_bus_writer
+//
+// WB Bus Master device to send a sequence of single-word transactions
+// based on a list in a RAM or ROM (FASM interface)
+// ROM data format is {WB_ADDR[15:0],WB_DATA[31:0]}
+// continues until it gets an all-1s entry
+
+module wb_bus_writer (input start,
+ output done,
+ output reg [15:0] rom_addr,
+ input [47:0] rom_data,
+ // WB Master Interface, don't need wb_dat_i
+ input wb_clk_i,
+ input wb_rst_i,
+ output [31:0] wb_dat_o,
+ input wb_ack_i,
+ output [15:0] wb_adr_o,
+ output wb_cyc_o,
+ output [3:0] wb_sel_o,
+ output wb_stb_o,
+ output wb_we_o
+ );
+
+`define IDLE 0
+`define READ 1
+
+ reg [3:0] state;
+
+ assign done = (state != `IDLE) && (&rom_data); // Done when we see all 1s
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ begin
+ rom_addr <= #1 0;
+ state <= #1 0;
+ end
+ else if(start)
+ begin
+ rom_addr <= #1 0;
+ state <= #1 `READ;
+ end
+ else if((state == `READ) && wb_ack_i)
+ if(done)
+ state <= #1 `IDLE;
+ else
+ rom_addr <= #1 rom_addr + 1;
+
+ assign wb_dat_o = rom_data[31:0];
+ assign wb_adr_o = rom_data[47:32];
+ assign wb_sel_o = 4'b1111; // All writes are the full 32 bits
+
+ assign wb_cyc_o = !done & (state != `IDLE);
+ assign wb_stb_o = !done & (state != `IDLE);
+ assign wb_we_o = !done & (state != `IDLE);
+
+endmodule // wb_bus_writer
diff --git a/fpga/usrp2/control_lib/wb_output_pins32.v b/fpga/usrp2/control_lib/wb_output_pins32.v
new file mode 100644
index 000000000..43e239797
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_output_pins32.v
@@ -0,0 +1,66 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Simple 32-bit Wishbone compatible slave output port
+// with 8-bit granularity, modeled after the one in the spec
+// Allows for readback
+// Assumes a 32-bit wishbone bus
+// Lowest order bits get sel[0]
+//
+
+module wb_output_pins32
+ (wb_rst_i, wb_clk_i, wb_dat_i, wb_dat_o,
+ wb_we_i, wb_sel_i, wb_stb_i, wb_ack_o, wb_cyc_i,
+ port_output);
+
+ input wb_rst_i;
+ input wb_clk_i;
+ input wire [31:0] wb_dat_i;
+ output wire [31:0] wb_dat_o;
+ input wb_we_i;
+ input wire [3:0] wb_sel_i;
+ input wb_stb_i;
+ output wb_ack_o;
+ input wb_cyc_i;
+
+ output wire [31:0] port_output;
+
+ reg [31:0] internal_reg;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ internal_reg <= #1 32'b0;
+ else
+ begin
+ if(wb_stb_i & wb_we_i & wb_sel_i[0])
+ internal_reg[7:0] <= #1 wb_dat_i[7:0];
+ if(wb_stb_i & wb_we_i & wb_sel_i[1])
+ internal_reg[15:8] <= #1 wb_dat_i[15:8];
+ if(wb_stb_i & wb_we_i & wb_sel_i[2])
+ internal_reg[23:16] <= #1 wb_dat_i[23:16];
+ if(wb_stb_i & wb_we_i & wb_sel_i[3])
+ internal_reg[31:24] <= #1 wb_dat_i[31:24];
+ end // else: !if(wb_rst_i)
+
+ assign wb_dat_o = internal_reg;
+ assign port_output = internal_reg;
+ assign wb_ack_o = wb_stb_i;
+
+endmodule // wb_output_pins32
+
diff --git a/fpga/usrp2/control_lib/wb_ram_block.v b/fpga/usrp2/control_lib/wb_ram_block.v
new file mode 100644
index 000000000..da6c610d3
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_ram_block.v
@@ -0,0 +1,53 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Since this is a block ram, there are no byte-selects and there is a 1-cycle read latency
+// These have to be a multiple of 512 lines (2K) long
+
+module wb_ram_block
+ #(parameter AWIDTH=9)
+ (input clk_i,
+ input stb_i,
+ input we_i,
+ input [AWIDTH-1:0] adr_i,
+ input [31:0] dat_i,
+ output reg [31:0] dat_o,
+ output ack_o);
+
+ reg [31:0] distram [0:1<<(AWIDTH-1)];
+
+ always @(posedge clk_i)
+ begin
+ if(stb_i & we_i)
+ distram[adr_i] <= dat_i;
+ dat_o <= distram[adr_i];
+ end
+
+ reg stb_d1, ack_d1;
+ always @(posedge clk_i)
+ stb_d1 <= stb_i;
+
+ always @(posedge clk_i)
+ ack_d1 <= ack_o;
+
+ assign ack_o = stb_i & (we_i | (stb_d1 & ~ack_d1));
+endmodule // wb_ram_block
+
+
+
diff --git a/fpga/usrp2/control_lib/wb_ram_dist.v b/fpga/usrp2/control_lib/wb_ram_dist.v
new file mode 100644
index 000000000..491a6ae11
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_ram_dist.v
@@ -0,0 +1,50 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module wb_ram_dist
+ #(parameter AWIDTH=8)
+ (input clk_i,
+ input stb_i,
+ input we_i,
+ input [AWIDTH-1:0] adr_i,
+ input [31:0] dat_i,
+ input [3:0] sel_i,
+ output [31:0] dat_o,
+ output ack_o);
+
+ reg [31:0] distram [0:1<<(AWIDTH-1)];
+
+ always @(posedge clk_i)
+ begin
+ if(stb_i & we_i & sel_i[3])
+ distram[adr_i][31:24] <= dat_i[31:24];
+ if(stb_i & we_i & sel_i[2])
+ distram[adr_i][24:16] <= dat_i[24:16];
+ if(stb_i & we_i & sel_i[1])
+ distram[adr_i][15:8] <= dat_i[15:8];
+ if(stb_i & we_i & sel_i[0])
+ distram[adr_i][7:0] <= dat_i[7:0];
+ end // always @ (posedge clk_i)
+
+ assign dat_o = distram[adr_i];
+ assign ack_o = stb_i;
+
+endmodule // wb_ram_dist
+
+
diff --git a/fpga/usrp2/control_lib/wb_readback_mux.v b/fpga/usrp2/control_lib/wb_readback_mux.v
new file mode 100644
index 000000000..a5bf224b8
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_readback_mux.v
@@ -0,0 +1,77 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Note -- clocks must be synchronous (derived from the same source)
+// Assumes alt_clk is running at a multiple of wb_clk
+
+module wb_readback_mux
+ (input wb_clk_i,
+ input wb_rst_i,
+ input wb_stb_i,
+ input [15:0] wb_adr_i,
+ output reg [31:0] wb_dat_o,
+ output reg wb_ack_o,
+
+ input [31:0] word00,
+ input [31:0] word01,
+ input [31:0] word02,
+ input [31:0] word03,
+ input [31:0] word04,
+ input [31:0] word05,
+ input [31:0] word06,
+ input [31:0] word07,
+ input [31:0] word08,
+ input [31:0] word09,
+ input [31:0] word10,
+ input [31:0] word11,
+ input [31:0] word12,
+ input [31:0] word13,
+ input [31:0] word14,
+ input [31:0] word15
+ );
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ wb_ack_o <= 0;
+ else
+ wb_ack_o <= wb_stb_i & ~wb_ack_o;
+
+ always @(posedge wb_clk_i)
+ case(wb_adr_i[5:2])
+ 0 : wb_dat_o <= word00;
+ 1 : wb_dat_o <= word01;
+ 2 : wb_dat_o <= word02;
+ 3 : wb_dat_o <= word03;
+ 4 : wb_dat_o <= word04;
+ 5 : wb_dat_o <= word05;
+ 6 : wb_dat_o <= word06;
+ 7 : wb_dat_o <= word07;
+ 8 : wb_dat_o <= word08;
+ 9 : wb_dat_o <= word09;
+ 10: wb_dat_o <= word10;
+ 11: wb_dat_o <= word11;
+ 12: wb_dat_o <= word12;
+ 13: wb_dat_o <= word13;
+ 14: wb_dat_o <= word14;
+ 15: wb_dat_o <= word15;
+ endcase // case(addr_reg[3:0])
+
+endmodule // wb_readback_mux
+
+
diff --git a/fpga/usrp2/control_lib/wb_readback_mux_16LE.v b/fpga/usrp2/control_lib/wb_readback_mux_16LE.v
new file mode 100644
index 000000000..aceec601b
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_readback_mux_16LE.v
@@ -0,0 +1,90 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+// Note -- clocks must be synchronous (derived from the same source)
+// Assumes alt_clk is running at a multiple of wb_clk
+
+// Note -- assumes that the lower-16 bits will be requested first,
+// and that the upper-16 bit request will come immediately after.
+
+module wb_readback_mux_16LE
+ (input wb_clk_i,
+ input wb_rst_i,
+ input wb_stb_i,
+ input [15:0] wb_adr_i,
+ output [15:0] wb_dat_o,
+ output reg wb_ack_o,
+
+ input [31:0] word00,
+ input [31:0] word01,
+ input [31:0] word02,
+ input [31:0] word03,
+ input [31:0] word04,
+ input [31:0] word05,
+ input [31:0] word06,
+ input [31:0] word07,
+ input [31:0] word08,
+ input [31:0] word09,
+ input [31:0] word10,
+ input [31:0] word11,
+ input [31:0] word12,
+ input [31:0] word13,
+ input [31:0] word14,
+ input [31:0] word15
+ );
+
+ wire ack_next = wb_stb_i & ~wb_ack_o;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ wb_ack_o <= 0;
+ else
+ wb_ack_o <= ack_next;
+
+ reg [31:0] data;
+ assign wb_dat_o = data[15:0];
+
+ always @(posedge wb_clk_i)
+ if (wb_adr_i[1] & ack_next) begin //upper half
+ data[15:0] <= data[31:16];
+ end
+ else if (~wb_adr_i[1] & ack_next) begin //lower half
+ case(wb_adr_i[5:2])
+ 0 : data <= word00;
+ 1 : data <= word01;
+ 2 : data <= word02;
+ 3 : data <= word03;
+ 4 : data <= word04;
+ 5 : data <= word05;
+ 6 : data <= word06;
+ 7 : data <= word07;
+ 8 : data <= word08;
+ 9 : data <= word09;
+ 10: data <= word10;
+ 11: data <= word11;
+ 12: data <= word12;
+ 13: data <= word13;
+ 14: data <= word14;
+ 15: data <= word15;
+ endcase // case(wb_adr_i[5:2])
+ end
+
+endmodule // wb_readback_mux
+
+
diff --git a/fpga/usrp2/control_lib/wb_regfile_2clock.v b/fpga/usrp2/control_lib/wb_regfile_2clock.v
new file mode 100644
index 000000000..ce93ab3f4
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_regfile_2clock.v
@@ -0,0 +1,124 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+module wb_regfile_2clock
+ (input wb_clk_i,
+ input wb_rst_i,
+ input wb_stb_i,
+ input wb_we_i,
+ input [15:0] wb_adr_i,
+ input [3:0] wb_sel_i,
+ input [31:0] wb_dat_i,
+ output [31:0] wb_dat_o,
+ output wb_ack_o,
+ input alt_clk,
+ input alt_rst,
+
+ output reg [31:0] reg00,
+ output reg [31:0] reg01,
+ output reg [31:0] reg02,
+ output reg [31:0] reg03,
+ output reg [31:0] reg04,
+ output reg [31:0] reg05,
+ output reg [31:0] reg06,
+ output reg [31:0] reg07
+ );
+
+ reg [15:0] addr_reg;
+ reg [3:0] sel_reg;
+ reg [31:0] dat_reg;
+ reg wr_ret1, wr_ret2, we_reg, stb_reg;
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ begin
+ addr_reg <= 0;
+ sel_reg <= 0;
+ dat_reg <= 0;
+ end
+ else if(wb_stb_i & wb_we_i)
+ begin
+ addr_reg <= wb_adr_i;
+ sel_reg <= wb_sel_i;
+ dat_reg <= wb_dat_i;
+ end
+
+ always @(posedge wb_clk_i)
+ if(wb_rst_i)
+ {we_reg,stb_reg} <= 2'b0;
+ else
+ {we_reg,stb_reg} <= {wb_we_i,wb_stb_i};
+
+ assign wb_ack_o = stb_reg;
+
+ always @(posedge alt_clk)
+ if(alt_rst)
+ {wr_ret2, wr_ret1} <= 2'b0;
+ else
+ {wr_ret2, wr_ret1} <= {wr_ret1, we_reg & stb_reg};
+
+ always @(posedge alt_clk)
+ if(alt_rst)
+ begin
+ reg00 <= 0;
+ reg01 <= 0;
+ reg02 <= 0;
+ reg03 <= 0;
+ reg04 <= 0;
+ reg05 <= 0;
+ reg06 <= 0;
+ reg07 <= 0;
+ end // if (alt_rst)
+ else if(wr_ret2)
+ case(addr_reg[4:2])
+ 3'd0: reg00 <= { {sel_reg[3] ? dat_reg[31:24] : reg00[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg00[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg00[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg00[7:0]}};
+ 3'd1: reg01 <= { {sel_reg[3] ? dat_reg[31:24] : reg01[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg01[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg01[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg01[7:0]}};
+ 3'd2: reg02 <= { {sel_reg[3] ? dat_reg[31:24] : reg02[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg02[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg02[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg02[7:0]}};
+ 3'd3: reg03 <= { {sel_reg[3] ? dat_reg[31:24] : reg03[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg03[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg03[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg03[7:0]}};
+ 3'd4: reg04 <= { {sel_reg[3] ? dat_reg[31:24] : reg04[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg04[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg04[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg04[7:0]}};
+ 3'd5: reg05 <= { {sel_reg[3] ? dat_reg[31:24] : reg05[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg05[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg05[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg05[7:0]}};
+ 3'd6: reg06 <= { {sel_reg[3] ? dat_reg[31:24] : reg06[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg06[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg06[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg06[7:0]}};
+ 3'd7: reg07 <= { {sel_reg[3] ? dat_reg[31:24] : reg07[31:24]},
+ {sel_reg[2] ? dat_reg[23:16] : reg07[23:16]},
+ {sel_reg[1] ? dat_reg[15:8] : reg07[15:8]},
+ {sel_reg[0] ? dat_reg[7:0] : reg07[7:0]}};
+ endcase // case(addr_reg[2:0])
+
+endmodule // wb_regfile_2clock
+
diff --git a/fpga/usrp2/control_lib/wb_semaphore.v b/fpga/usrp2/control_lib/wb_semaphore.v
new file mode 100644
index 000000000..e90950509
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_semaphore.v
@@ -0,0 +1,59 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+// up to 8 semaphores
+
+// After a read operation, the semaphore is always locked
+// If it was already locked before the read (meaning someone else holds the lock)
+// then a 1 is returned
+// If it was not already locked (meaning the reader now holds the lock)
+// then a 0 is returned
+
+// A write operation clears the lock
+
+module wb_semaphore
+ #(parameter count=8, DBUS_WIDTH=32)
+ (input wb_clk_i,
+ input wb_rst_i,
+ input [DBUS_WIDTH-1:0] wb_dat_i,
+ input [2:0] wb_adr_i,
+ input wb_cyc_i,
+ input wb_stb_i,
+ input wb_we_i,
+ output wb_ack_o,
+ output [DBUS_WIDTH-1:0] wb_dat_o);
+
+ reg [count-1:0] locked;
+
+ always @(posedge clock)
+ if(wb_rst_i)
+ locked <= {count{1'b0}};
+ else if(wb_stb_i)
+ if(wb_we_i)
+ locked[adr_i] <= 1'b0;
+ else
+ locked[adr_i] <= 1'b1;
+
+ assign wb_dat_o[DBUS_WIDTH-1:1] = {(DBUS_WIDTH-1){1'b0}};
+ assign wb_dat_o[0] = locked[adr_i];
+ assign wb_ack_o = wb_stb_i;
+
+
+endmodule // wb_semaphore
+
+
diff --git a/fpga/usrp2/control_lib/wb_sim.v b/fpga/usrp2/control_lib/wb_sim.v
new file mode 100644
index 000000000..9f2fbea54
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_sim.v
@@ -0,0 +1,96 @@
+//
+// Copyright 2011 Ettus Research LLC
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+//
+
+
+
+module wb_sim();
+
+ wire wb_clk, wb_rst;
+ wire start;
+
+ reg POR, aux_clk, clk_fpga;
+
+ initial POR = 1'b1;
+ initial #103 POR = 1'b0;
+
+ initial aux_clk = 1'b0;
+ always #25 aux_clk = ~aux_clk;
+
+ initial clk_fpga = 1'bx;
+ initial #3007 clk_fpga = 1'b0;
+ always #7 clk_fpga = ~clk_fpga;
+
+ initial begin
+ $dumpfile("wb_sim.vcd");
+ $dumpvars(0,wb_sim);
+ end
+
+ initial #10000 $finish;
+
+ wire [15:0] rom_addr;
+ wire [47:0] rom_data;
+ wire [31:0] wb_dat;
+ wire [15:0] wb_adr;
+ wire wb_cyc,wb_stb,wb_we,wb_ack;
+ wire [3:0] wb_sel;
+
+ wire [31:0] port_output;
+
+
+ system_control system_control(.dsp_clk(dsp_clk),
+ .reset_out(reset_out),
+ .wb_clk_o(wb_clk),
+ .wb_rst_o(wb_rst),
+ .wb_rst_o_alt(wb_rst_o_alt),
+ .start (start),
+ .aux_clk(aux_clk),
+ .clk_fpga(clk_fpga),
+ .POR (POR),
+ .done (done));
+
+ clock_bootstrap_rom cbrom(.addr(rom_addr),.data(rom_data));
+
+ wb_bus_writer bus_writer(.rom_addr (rom_addr[15:0]),
+ .wb_dat_o (wb_dat[31:0]),
+ .wb_adr_o (wb_adr[15:0]),
+ .wb_cyc_o (wb_cyc),
+ .wb_sel_o (wb_sel[3:0]),
+ .wb_stb_o (wb_stb),
+ .wb_we_o (wb_we),
+ .start (start),
+ .done (done),
+ .rom_data (rom_data[47:0]),
+ .wb_clk_i (wb_clk),
+ .wb_rst_i (wb_rst),
+ .wb_ack_i (wb_ack));
+
+ wb_output_pins32 output_pins(.wb_dat_o(),
+ .wb_ack_o(wb_ack),
+ .port_output(port_output[31:0]),
+ .wb_rst_i(wb_rst),
+ .wb_clk_i(wb_clk),
+ .wb_dat_i(wb_dat[31:0]),
+ .wb_we_i(wb_we),
+ .wb_sel_i(wb_sel[3:0]),
+ .wb_stb_i(wb_stb),
+ .wb_cyc_i(wb_cyc));
+
+
+
+
+endmodule // wb_sim
+