aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp2/control_lib
diff options
context:
space:
mode:
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.srcs53
-rw-r--r--fpga/usrp2/control_lib/atr_controller.v57
-rw-r--r--fpga/usrp2/control_lib/atr_controller16.v60
-rw-r--r--fpga/usrp2/control_lib/bin2gray.v10
-rw-r--r--fpga/usrp2/control_lib/bootram.v250
-rw-r--r--fpga/usrp2/control_lib/bootrom.mem26
-rw-r--r--fpga/usrp2/control_lib/clock_bootstrap_rom.v34
-rw-r--r--fpga/usrp2/control_lib/clock_control.v115
-rw-r--r--fpga/usrp2/control_lib/clock_control_tb.v35
-rw-r--r--fpga/usrp2/control_lib/cmdfile18
-rw-r--r--fpga/usrp2/control_lib/dcache.v165
-rw-r--r--fpga/usrp2/control_lib/decoder_3_8.v21
-rw-r--r--fpga/usrp2/control_lib/dpram32.v82
-rw-r--r--fpga/usrp2/control_lib/fifo_tb.v151
-rw-r--r--fpga/usrp2/control_lib/gray2bin.v13
-rw-r--r--fpga/usrp2/control_lib/gray_send.v29
-rw-r--r--fpga/usrp2/control_lib/icache.v135
-rw-r--r--fpga/usrp2/control_lib/longfifo.v150
-rw-r--r--fpga/usrp2/control_lib/medfifo.v49
-rw-r--r--fpga/usrp2/control_lib/mux4.v16
-rw-r--r--fpga/usrp2/control_lib/mux8.v21
-rw-r--r--fpga/usrp2/control_lib/mux_32_4.v13
-rw-r--r--fpga/usrp2/control_lib/nsgpio.v107
-rw-r--r--fpga/usrp2/control_lib/nsgpio16LE.v123
-rw-r--r--fpga/usrp2/control_lib/oneshot_2clk.v35
-rw-r--r--fpga/usrp2/control_lib/pic.v183
-rw-r--r--fpga/usrp2/control_lib/priority_enc.v44
-rw-r--r--fpga/usrp2/control_lib/quad_uart.v71
-rw-r--r--fpga/usrp2/control_lib/ram_2port.v42
-rw-r--r--fpga/usrp2/control_lib/ram_2port_mixed_width.v120
-rw-r--r--fpga/usrp2/control_lib/ram_harv_cache.v75
-rw-r--r--fpga/usrp2/control_lib/ram_harvard.v69
-rw-r--r--fpga/usrp2/control_lib/ram_harvard2.v77
-rw-r--r--fpga/usrp2/control_lib/ram_loader.v261
-rw-r--r--fpga/usrp2/control_lib/ram_wb_harvard.v86
-rw-r--r--fpga/usrp2/control_lib/reset_sync.v16
-rw-r--r--fpga/usrp2/control_lib/s3a_icap_wb.v59
-rw-r--r--fpga/usrp2/control_lib/sd_spi.v70
-rw-r--r--fpga/usrp2/control_lib/sd_spi_tb.v40
-rw-r--r--fpga/usrp2/control_lib/sd_spi_wb.v76
-rw-r--r--fpga/usrp2/control_lib/setting_reg.v25
-rw-r--r--fpga/usrp2/control_lib/settings_bus.v41
-rw-r--r--fpga/usrp2/control_lib/settings_bus_16LE.v54
-rw-r--r--fpga/usrp2/control_lib/settings_bus_crossclock.v20
-rw-r--r--fpga/usrp2/control_lib/shortfifo.v87
-rw-r--r--fpga/usrp2/control_lib/simple_uart.v62
-rw-r--r--fpga/usrp2/control_lib/simple_uart_rx.v64
-rw-r--r--fpga/usrp2/control_lib/simple_uart_tx.v60
-rw-r--r--fpga/usrp2/control_lib/spi.v84
-rw-r--r--fpga/usrp2/control_lib/srl.v21
-rw-r--r--fpga/usrp2/control_lib/ss_rcvr.v81
-rw-r--r--fpga/usrp2/control_lib/system_control.v47
-rw-r--r--fpga/usrp2/control_lib/system_control_tb.v57
-rw-r--r--fpga/usrp2/control_lib/traffic_cop.v25
-rw-r--r--fpga/usrp2/control_lib/v5icap_wb.v54
-rw-r--r--fpga/usrp2/control_lib/wb_1master.v464
-rw-r--r--fpga/usrp2/control_lib/wb_bridge_16_32.v36
-rw-r--r--fpga/usrp2/control_lib/wb_bus_writer.v57
-rw-r--r--fpga/usrp2/control_lib/wb_output_pins32.v49
-rw-r--r--fpga/usrp2/control_lib/wb_ram_block.v36
-rw-r--r--fpga/usrp2/control_lib/wb_ram_dist.v33
-rw-r--r--fpga/usrp2/control_lib/wb_readback_mux.v60
-rw-r--r--fpga/usrp2/control_lib/wb_readback_mux_16LE.v73
-rw-r--r--fpga/usrp2/control_lib/wb_regfile_2clock.v107
-rw-r--r--fpga/usrp2/control_lib/wb_semaphore.v42
-rw-r--r--fpga/usrp2/control_lib/wb_sim.v79
68 files changed, 4969 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..751b40828
--- /dev/null
+++ b/fpga/usrp2/control_lib/Makefile.srcs
@@ -0,0 +1,53 @@
+#
+# Copyright 2010 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 \
+dpram32.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 \
+))
diff --git a/fpga/usrp2/control_lib/atr_controller.v b/fpga/usrp2/control_lib/atr_controller.v
new file mode 100644
index 000000000..fed2791f9
--- /dev/null
+++ b/fpga/usrp2/control_lib/atr_controller.v
@@ -0,0 +1,57 @@
+
+// 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, input [31:0] master_time,
+ 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)
+
+ always @(posedge clk_i)
+ dat_o <= atr_ram[adr_i[5:2]];
+
+ 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..3d8b5b1e9
--- /dev/null
+++ b/fpga/usrp2/control_lib/atr_controller16.v
@@ -0,0 +1,60 @@
+
+// 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 reg [15:0] dat_o,
+ input we_i, input stb_i, input cyc_i, output reg ack_o,
+ input run_rx, input run_tx, input [31:0] master_time,
+ 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)
+
+ 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];
+
+ 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..513402163
--- /dev/null
+++ b/fpga/usrp2/control_lib/bin2gray.v
@@ -0,0 +1,10 @@
+
+
+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..668012504
--- /dev/null
+++ b/fpga/usrp2/control_lib/bootram.v
@@ -0,0 +1,250 @@
+
+// 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 [12:0] if_adr,
+ output [31:0] if_data,
+
+ input [12: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;
+ wire [31:0] DOB0, DOB1, DOB2, DOB3;
+ wire ENB0, ENB1, ENB2, ENB3;
+ wire [3:0] WEB;
+
+ reg [1:0] delayed_if_bank;
+ always @(posedge clk)
+ delayed_if_bank <= if_adr[12:11];
+
+ assign if_data = delayed_if_bank[1] ? (delayed_if_bank[0] ? DOA3 : DOA2) : (delayed_if_bank[0] ? DOA1 : DOA0);
+ assign dwb_dat_o = 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[12:11] == 2'b00);
+ assign ENB1 = dwb_stb_i & (dwb_adr_i[12:11] == 2'b01);
+ assign ENB2 = dwb_stb_i & (dwb_adr_i[12:11] == 2'b10);
+ assign ENB3 = dwb_stb_i & (dwb_adr_i[12:11] == 2'b11);
+
+ 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'd0), // Port A 32-bit Data Input
+ .DIPA(4'd0), // 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'd0), // 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'd0), // Port A 32-bit Data Input
+ .DIPA(4'd0), // 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'd0), // 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'd0), // Port A 32-bit Data Input
+ .DIPA(4'd0), // 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'd0), // 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'd0), // Port A 32-bit Data Input
+ .DIPA(4'd0), // 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'd0), // 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
+
+endmodule // bootram
+
+/*
+ // The following INIT_xx declarations specify the initial contents of the RAM
+ // Address 0 to 127
+ .INIT_00(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_01(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_02(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_03(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_04(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_05(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_06(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_07(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_08(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_09(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0A(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0B(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0C(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0D(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0E(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_0F(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ // Address 128 to 255
+ .INIT_10(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_11(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_12(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_13(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_14(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_15(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_16(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_17(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_18(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_19(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1A(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1B(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1C(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1D(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1E(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_1F(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ // Address 256 to 383
+ .INIT_20(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_21(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_22(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_23(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_24(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_25(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_26(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_27(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_28(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_29(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2A(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2B(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2C(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2D(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2E(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_2F(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ // Address 384 to 511
+ .INIT_30(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_31(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_32(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_33(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_34(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_35(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_36(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_37(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_38(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_39(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3A(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3B(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3C(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3D(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3E(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ .INIT_3F(256’h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000),
+ // The next set of INITP_xx are for the parity bits
+ // Address 0 to 127
+ .INITP_00(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ .INITP_01(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ // Address 128 to 255
+ .INITP_02(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ .INITP_03(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ // Address 256 to 383
+ .INITP_04(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ .INITP_05(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ // Address 384 to 511
+ .INITP_06(256’h0000000000000000000000000000000000000000000000000000000000000000),
+ .INITP_07(256’h0000000000000000000000000000000000000000000000000000000000000000)
+*/
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..46563db65
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_bootstrap_rom.v
@@ -0,0 +1,34 @@
+
+
+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..1bbe6bd75
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_control.v
@@ -0,0 +1,115 @@
+
+
+// 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..4e705cf23
--- /dev/null
+++ b/fpga/usrp2/control_lib/clock_control_tb.v
@@ -0,0 +1,35 @@
+
+
+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/dcache.v b/fpga/usrp2/control_lib/dcache.v
new file mode 100644
index 000000000..9063bf02a
--- /dev/null
+++ b/fpga/usrp2/control_lib/dcache.v
@@ -0,0 +1,165 @@
+
+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..729b45d18
--- /dev/null
+++ b/fpga/usrp2/control_lib/decoder_3_8.v
@@ -0,0 +1,21 @@
+
+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/dpram32.v b/fpga/usrp2/control_lib/dpram32.v
new file mode 100644
index 000000000..4da621823
--- /dev/null
+++ b/fpga/usrp2/control_lib/dpram32.v
@@ -0,0 +1,82 @@
+
+// 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_tb.v b/fpga/usrp2/control_lib/fifo_tb.v
new file mode 100644
index 000000000..616fe4ee7
--- /dev/null
+++ b/fpga/usrp2/control_lib/fifo_tb.v
@@ -0,0 +1,151 @@
+module fifo_tb();
+
+ reg clk, rst;
+ wire short_full, short_empty, long_full, long_empty;
+ wire casc2_full, casc2_empty;
+ reg read, write;
+
+ wire [7:0] short_do, long_do;
+ wire [7:0] casc2_do;
+ reg [7:0] di;
+
+ reg clear = 0;
+
+ shortfifo #(.WIDTH(8)) shortfifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(short_do),.clear(clear),
+ .read(read),.write(write),.full(short_full),.empty(short_empty));
+
+ longfifo #(.WIDTH(8), .SIZE(4)) longfifo
+ (.clk(clk),.rst(rst),.datain(di),.dataout(long_do),.clear(clear),
+ .read(read),.write(write),.full(long_full),.empty(long_empty));
+
+ cascadefifo2 #(.WIDTH(8), .SIZE(4)) cascadefifo2
+ (.clk(clk),.rst(rst),.datain(di),.dataout(casc2_do),.clear(clear),
+ .read(read),.write(write),.full(casc2_full),.empty(casc2_empty));
+
+ initial rst = 1;
+ initial #1000 rst = 0;
+ initial clk = 0;
+ always #50 clk = ~clk;
+
+ initial di = 8'hAE;
+ initial read = 0;
+ initial write = 0;
+
+ always @(posedge clk)
+ if(write)
+ di <= di + 1;
+
+ always @(posedge clk)
+ begin
+ if(short_full != long_full)
+ $display("Error: FULL mismatch");
+ if(short_empty != long_empty)
+ $display("Note: EMPTY mismatch, usually not a problem (longfifo has 2 cycle latency)");
+ if(read & (short_do != long_do))
+ $display("Error: DATA mismatch");
+ end
+
+ initial $dumpfile("fifo_tb.vcd");
+ initial $dumpvars(0,fifo_tb);
+
+ initial
+ begin
+ @(negedge rst);
+ @(posedge clk);
+ repeat (10)
+ @(posedge clk);
+ write <= 1;
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+
+ repeat(10)
+ begin
+ write <= 1;
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ end // repeat (10)
+
+ write <= 1;
+ repeat (4)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ read <= 1;
+ repeat (4)
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+
+ write <= 1;
+ repeat (4)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ repeat (4)
+ begin
+ read <= 1;
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+ end
+
+ write <= 1;
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ @(posedge clk);
+ read <= 1;
+ repeat (5)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+ write <= 1;
+ repeat (16)
+ @(posedge clk);
+ write <= 0;
+ @(posedge clk);
+
+ read <= 1;
+ repeat (16)
+ @(posedge clk);
+ read <= 0;
+ @(posedge clk);
+
+ repeat (10)
+ @(posedge clk);
+ $finish;
+ end
+endmodule // longfifo_tb
diff --git a/fpga/usrp2/control_lib/gray2bin.v b/fpga/usrp2/control_lib/gray2bin.v
new file mode 100644
index 000000000..5df40bd52
--- /dev/null
+++ b/fpga/usrp2/control_lib/gray2bin.v
@@ -0,0 +1,13 @@
+
+
+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..7fc07d40c
--- /dev/null
+++ b/fpga/usrp2/control_lib/gray_send.v
@@ -0,0 +1,29 @@
+
+
+
+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..bd21f47cc
--- /dev/null
+++ b/fpga/usrp2/control_lib/icache.v
@@ -0,0 +1,135 @@
+
+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..bf3338e0b
--- /dev/null
+++ b/fpga/usrp2/control_lib/longfifo.v
@@ -0,0 +1,150 @@
+
+// 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..5a77e8c16
--- /dev/null
+++ b/fpga/usrp2/control_lib/medfifo.v
@@ -0,0 +1,49 @@
+
+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..31c85c832
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux4.v
@@ -0,0 +1,16 @@
+
+
+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..9db96a60f
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux8.v
@@ -0,0 +1,21 @@
+
+
+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..fef5812e9
--- /dev/null
+++ b/fpga/usrp2/control_lib/mux_32_4.v
@@ -0,0 +1,13 @@
+
+
+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..26130cc8e
--- /dev/null
+++ b/fpga/usrp2/control_lib/nsgpio.v
@@ -0,0 +1,107 @@
+// 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 [3:0] adr_i, input we_i, input [31:0] dat_i,
+ output reg [31: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 [63:0] ctrl;
+ reg [31:0] line;
+ reg [31:0] lgpio; // LatchedGPIO pins
+ reg [31:0] ddr;
+
+ 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 <= 64'h0;
+ line <= 0;
+ end
+ else if (wb_wr)
+ case( adr_i[3:2] )
+ 2'b00 :
+ line <= dat_i;
+ 2'b01 :
+ ddr[31:0] <= dat_i;
+ 2'b10 :
+ ctrl[63:32] <= dat_i;
+ 2'b11 :
+ ctrl[31:0] <= dat_i;
+ endcase // case( adr_i[3:2] )
+
+ always @(posedge clk_i)
+ case (adr_i[3:2])
+ 2'b00 :
+ dat_o <= lgpio;
+ 2'b01 :
+ dat_o <= ddr;
+ 2'b10 :
+ dat_o <= ctrl[63:32];
+ 2'b11 :
+ dat_o <= ctrl[31:0];
+ endcase // case(adr_i[3:2])
+
+ 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)
+ for(n=0;n<32;n=n+1)
+ igpio[n] <= ddr[n] ? (ctrl[2*n+1] ? (ctrl[2*n] ? debug_1[n] : debug_0[n]) :
+ (ctrl[2*n] ? atr[n] : line[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..72f16a4b3
--- /dev/null
+++ b/fpga/usrp2/control_lib/oneshot_2clk.v
@@ -0,0 +1,35 @@
+
+// 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..916192445
--- /dev/null
+++ b/fpga/usrp2/control_lib/priority_enc.v
@@ -0,0 +1,44 @@
+
+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..afa6fae1d
--- /dev/null
+++ b/fpga/usrp2/control_lib/quad_uart.v
@@ -0,0 +1,71 @@
+
+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..3716a7c8a
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_2port.v
@@ -0,0 +1,42 @@
+
+
+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..fae7d8de3
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_2port_mixed_width.v
@@ -0,0 +1,120 @@
+
+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..29fdebf7a
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harv_cache.v
@@ -0,0 +1,75 @@
+
+
+// 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..948f9b36f
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harvard.v
@@ -0,0 +1,69 @@
+
+
+// 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,
+
+ input flush_icache );
+
+ 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..67777af2a
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_harvard2.v
@@ -0,0 +1,77 @@
+
+
+// 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..c53ea7aa7
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_loader.v
@@ -0,0 +1,261 @@
+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..c3efc12e0
--- /dev/null
+++ b/fpga/usrp2/control_lib/ram_wb_harvard.v
@@ -0,0 +1,86 @@
+
+// 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..94d966840
--- /dev/null
+++ b/fpga/usrp2/control_lib/reset_sync.v
@@ -0,0 +1,16 @@
+
+
+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..83d9f775e
--- /dev/null
+++ b/fpga/usrp2/control_lib/s3a_icap_wb.v
@@ -0,0 +1,59 @@
+
+
+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..3f4d7f46a
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi.v
@@ -0,0 +1,70 @@
+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..e30a5bdf6
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi_tb.v
@@ -0,0 +1,40 @@
+
+
+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..7a6258b56
--- /dev/null
+++ b/fpga/usrp2/control_lib/sd_spi_wb.v
@@ -0,0 +1,76 @@
+
+// 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..3d3bb65e5
--- /dev/null
+++ b/fpga/usrp2/control_lib/setting_reg.v
@@ -0,0 +1,25 @@
+
+
+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..aec179516
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus.v
@@ -0,0 +1,41 @@
+
+// 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..76061e9e0
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus_16LE.v
@@ -0,0 +1,54 @@
+
+// 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..b043aa0ad
--- /dev/null
+++ b/fpga/usrp2/control_lib/settings_bus_crossclock.v
@@ -0,0 +1,20 @@
+
+
+// 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
+ (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);
+
+ 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(~empty), .empty(empty));
+
+ assign set_stb_o = ~empty;
+
+endmodule // settings_bus_crossclock
diff --git a/fpga/usrp2/control_lib/shortfifo.v b/fpga/usrp2/control_lib/shortfifo.v
new file mode 100644
index 000000000..d8ce1428e
--- /dev/null
+++ b/fpga/usrp2/control_lib/shortfifo.v
@@ -0,0 +1,87 @@
+
+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_uart.v b/fpga/usrp2/control_lib/simple_uart.v
new file mode 100644
index 000000000..0dd58b5f5
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart.v
@@ -0,0 +1,62 @@
+
+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..debdd618b
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart_rx.v
@@ -0,0 +1,64 @@
+
+
+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..e11a347ed
--- /dev/null
+++ b/fpga/usrp2/control_lib/simple_uart_tx.v
@@ -0,0 +1,60 @@
+
+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..a80c488e9
--- /dev/null
+++ b/fpga/usrp2/control_lib/spi.v
@@ -0,0 +1,84 @@
+
+
+// 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..fa28c7669
--- /dev/null
+++ b/fpga/usrp2/control_lib/srl.v
@@ -0,0 +1,21 @@
+
+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..8e650d21b
--- /dev/null
+++ b/fpga/usrp2/control_lib/ss_rcvr.v
@@ -0,0 +1,81 @@
+
+
+// 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..5d89f13db
--- /dev/null
+++ b/fpga/usrp2/control_lib/system_control.v
@@ -0,0 +1,47 @@
+// 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..a8eff4811
--- /dev/null
+++ b/fpga/usrp2/control_lib/system_control_tb.v
@@ -0,0 +1,57 @@
+
+
+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..e7579656a
--- /dev/null
+++ b/fpga/usrp2/control_lib/traffic_cop.v
@@ -0,0 +1,25 @@
+
+module traffic_cop();
+
+
+endmodule // traffic_cop
+
+
+
+/*
+
+ Traffic Cop to control buffer pool
+
+ Inputs
+
+ Commands
+
+ Basic Operations
+
+ Outputs
+
+
+
+
+
+ */
diff --git a/fpga/usrp2/control_lib/v5icap_wb.v b/fpga/usrp2/control_lib/v5icap_wb.v
new file mode 100644
index 000000000..c8800285a
--- /dev/null
+++ b/fpga/usrp2/control_lib/v5icap_wb.v
@@ -0,0 +1,54 @@
+
+
+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..405e25c3c
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_bridge_16_32.v
@@ -0,0 +1,36 @@
+
+
+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..fc148a0ff
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_bus_writer.v
@@ -0,0 +1,57 @@
+
+// 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..1517f2066
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_output_pins32.v
@@ -0,0 +1,49 @@
+
+
+// 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..044d34ca4
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_ram_block.v
@@ -0,0 +1,36 @@
+
+
+// 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..cffc2f423
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_ram_dist.v
@@ -0,0 +1,33 @@
+
+
+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..3922b03e3
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_readback_mux.v
@@ -0,0 +1,60 @@
+
+
+// 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..2b01898c1
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_readback_mux_16LE.v
@@ -0,0 +1,73 @@
+
+
+// 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..e248e5161
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_regfile_2clock.v
@@ -0,0 +1,107 @@
+
+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..a9208e6a1
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_semaphore.v
@@ -0,0 +1,42 @@
+
+// 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..b324e1457
--- /dev/null
+++ b/fpga/usrp2/control_lib/wb_sim.v
@@ -0,0 +1,79 @@
+
+
+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
+