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