diff options
Diffstat (limited to 'fpga/usrp2/control_lib')
69 files changed, 6167 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..a1c11c026 --- /dev/null +++ b/fpga/usrp2/control_lib/Makefile.srcs @@ -0,0 +1,54 @@ +# +# Copyright 2010 Ettus Research LLC +# + +################################################## +# Control Lib Sources +################################################## +CONTROL_LIB_SRCS = $(abspath $(addprefix $(BASE_DIR)/../control_lib/, \ +CRC16_D16.v \ +atr_controller.v \ +bin2gray.v \ +dcache.v \ +decoder_3_8.v \ +dpram32.v \ +gray2bin.v \ +gray_send.v \ +icache.v \ +mux4.v \ +mux8.v \ +nsgpio.v \ +ram_2port.v \ +ram_harv_cache.v \ +ram_harvard.v \ +ram_harvard2.v \ +ram_loader.v \ +setting_reg.v \ +settings_bus.v \ +settings_bus_crossclock.v \ +srl.v \ +system_control.v \ +wb_1master.v \ +wb_readback_mux.v \ +wb_readback_mux_16LE.v \ +quad_uart.v \ +simple_uart.v \ +simple_uart_tx.v \ +simple_uart_rx.v \ +oneshot_2clk.v \ +sd_spi.v \ +sd_spi_wb.v \ +wb_bridge_16_32.v \ +reset_sync.v \ +priority_enc.v \ +pic.v \ +longfifo.v \ +shortfifo.v \ +medfifo.v \ +s3a_icap_wb.v \ +bootram.v \ +nsgpio16LE.v \ +settings_bus_16LE.v \ +atr_controller16.v \ +fifo_to_wb.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..2cef8ba2b --- /dev/null +++ b/fpga/usrp2/control_lib/atr_controller.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/>. +// + + +// 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) + + always @(posedge clk_i) + dat_o <= atr_ram[adr_i[5:2]]; + + always @(posedge clk_i) + ack_o <= stb_i & cyc_i & ~ack_o; + + // Control side of DP RAM + assign ctrl_lines = atr_ram[state]; + + // Put a more complex state machine with time delays and multiple states here + // if daughterboard requires more complex sequencing + localparam ATR_IDLE = 4'd0; + localparam ATR_TX = 4'd1; + localparam ATR_RX = 4'd2; + localparam ATR_FULL_DUPLEX = 4'd3; + + always @(posedge clk_i) + if(rst_i) + state <= ATR_IDLE; + else + case ({run_rx,run_tx}) + 2'b00 : state <= ATR_IDLE; + 2'b01 : state <= ATR_TX; + 2'b10 : state <= ATR_RX; + 2'b11 : state <= ATR_FULL_DUPLEX; + endcase // case({run_rx,run_tx}) + +endmodule // atr_controller diff --git a/fpga/usrp2/control_lib/atr_controller16.v b/fpga/usrp2/control_lib/atr_controller16.v new file mode 100644 index 000000000..ff4f634c7 --- /dev/null +++ b/fpga/usrp2/control_lib/atr_controller16.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_controller16 + (input clk_i, input rst_i, + input [5:0] adr_i, input [1:0] sel_i, input [15:0] dat_i, output reg [15:0] dat_o, + input we_i, input stb_i, input cyc_i, output reg ack_o, + input run_rx, input run_tx, + output [31:0] ctrl_lines); + + reg [3:0] state; + reg [31:0] atr_ram [0:15]; // DP distributed RAM + + wire [3:0] sel_int = { (sel_i[1] & adr_i[1]), (sel_i[0] & adr_i[1]), + (sel_i[1] & ~adr_i[1]), (sel_i[0] & ~adr_i[1]) }; + + // WB Interface + always @(posedge clk_i) + if(we_i & stb_i & cyc_i) + begin + if(sel_int[3]) + atr_ram[adr_i[5:2]][31:24] <= dat_i[15:8]; + if(sel_int[2]) + atr_ram[adr_i[5:2]][23:16] <= dat_i[7:0]; + if(sel_int[1]) + atr_ram[adr_i[5:2]][15:8] <= dat_i[15:8]; + if(sel_int[0]) + atr_ram[adr_i[5:2]][7:0] <= dat_i[7:0]; + end // if (we_i & stb_i & cyc_i) + + always @(posedge clk_i) + dat_o <= adr_i[1] ? atr_ram[adr_i[5:2]][31:16] : atr_ram[adr_i[5:2]][15:0]; + + always @(posedge clk_i) + ack_o <= stb_i & cyc_i & ~ack_o; + + // Control side of DP RAM + assign ctrl_lines = atr_ram[state]; + + // Put a more complex state machine with time delays and multiple states here + // if daughterboard requires more complex sequencing + localparam ATR_IDLE = 4'd0; + localparam ATR_TX = 4'd1; + localparam ATR_RX = 4'd2; + localparam ATR_FULL_DUPLEX = 4'd3; + + always @(posedge clk_i) + if(rst_i) + state <= ATR_IDLE; + else + case ({run_rx,run_tx}) + 2'b00 : state <= ATR_IDLE; + 2'b01 : state <= ATR_TX; + 2'b10 : state <= ATR_RX; + 2'b11 : state <= ATR_FULL_DUPLEX; + endcase // case({run_rx,run_tx}) + +endmodule // atr_controller16 diff --git a/fpga/usrp2/control_lib/bin2gray.v b/fpga/usrp2/control_lib/bin2gray.v new file mode 100644 index 000000000..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..249a09814 --- /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'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(DOB0), // Port B 32-bit Data Output + .DOPB(), // Port B 4-bit Parity Output + .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input + .CLKB(clk), // Port B 1-bit Clock + .DIB(dwb_dat_i), // Port B 32-bit Data Input + .DIPB(4'd0), // Port-B 4-bit parity Input + .ENB(ENB0), // Port B 1-bit RAM Enable Input + .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input + .WEB(WEB) // Port B 4-bit Write Enable Input + ); // End of RAMB16BWE_S36_S36_inst instantiation + + RAMB16BWE_S36_S36 + #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup + .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup + .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL" + .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion + .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion + .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE + .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE + RAM1 + (.DOA(DOA1), // Port A 32-bit Data Output + .DOPA(), // Port A 4-bit Parity Output + .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input + .CLKA(clk), // Port A 1-bit Clock + .DIA(32'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(DOB1), // Port B 32-bit Data Output + .DOPB(), // Port B 4-bit Parity Output + .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input + .CLKB(clk), // Port B 1-bit Clock + .DIB(dwb_dat_i), // Port B 32-bit Data Input + .DIPB(4'd0), // Port-B 4-bit parity Input + .ENB(ENB1), // Port B 1-bit RAM Enable Input + .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input + .WEB(WEB) // Port B 4-bit Write Enable Input + ); // End of RAMB16BWE_S36_S36_inst instantiation + + RAMB16BWE_S36_S36 + #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup + .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup + .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL" + .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion + .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion + .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE + .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE + RAM2 + (.DOA(DOA2), // Port A 32-bit Data Output + .DOPA(), // Port A 4-bit Parity Output + .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input + .CLKA(clk), // Port A 1-bit Clock + .DIA(32'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(DOB2), // Port B 32-bit Data Output + .DOPB(), // Port B 4-bit Parity Output + .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input + .CLKB(clk), // Port B 1-bit Clock + .DIB(dwb_dat_i), // Port B 32-bit Data Input + .DIPB(4'd0), // Port-B 4-bit parity Input + .ENB(ENB2), // Port B 1-bit RAM Enable Input + .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input + .WEB(WEB) // Port B 4-bit Write Enable Input + ); // End of RAMB16BWE_S36_S36_inst instantiation + + RAMB16BWE_S36_S36 + #(.INIT_A(36'h000000000), // Value of output RAM registers on Port A at startup + .INIT_B(36'h000000000), // Value of output RAM registers on Port B at startup + .SIM_COLLISION_CHECK("ALL"), // "NONE", "WARNING_ONLY", "GENERATE_X_ONLY", "ALL" + .SRVAL_A(36'h000000000), // Port A output value upon SSR assertion + .SRVAL_B(36'h000000000), // Port B output value upon SSR assertion + .WRITE_MODE_A("WRITE_FIRST"), // WRITE_FIRST, READ_FIRST or NO_CHANGE + .WRITE_MODE_B("WRITE_FIRST")) // WRITE_FIRST, READ_FIRST or NO_CHANGE + RAM3 + (.DOA(DOA3), // Port A 32-bit Data Output + .DOPA(), // Port A 4-bit Parity Output + .ADDRA(if_adr[10:2]), // Port A 9-bit Address Input + .CLKA(clk), // Port A 1-bit Clock + .DIA(32'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(DOB3), // Port B 32-bit Data Output + .DOPB(), // Port B 4-bit Parity Output + .ADDRB(dwb_adr_i[10:2]), // Port B 9-bit Address Input + .CLKB(clk), // Port B 1-bit Clock + .DIB(dwb_dat_i), // Port B 32-bit Data Input + .DIPB(4'd0), // Port-B 4-bit parity Input + .ENB(ENB3), // Port B 1-bit RAM Enable Input + .SSRB(1'b0), // Port B 1-bit Synchronous Set/Reset Input + .WEB(WEB) // Port B 4-bit Write Enable Input + ); // End of RAMB16BWE_S36_S36_inst instantiation + + 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'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(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'd0), // 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'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(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'd0), // 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'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(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'd0), // 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'd0), // Port A 32-bit Data Input + .DIPA(4'd0), // Port A 4-bit parity Input + .ENA(1'b1), // Port A 1-bit RAM Enable Input + .SSRA(1'b0), // Port A 1-bit Synchronous Set/Reset Input + .WEA(1'b0), // Port A 4-bit Write Enable Input + + .DOB(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'd0), // 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/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/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/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..26130cc8e --- /dev/null +++ b/fpga/usrp2/control_lib/nsgpio.v @@ -0,0 +1,107 @@ +// Modified from code originally by Richard Herveille, his copyright is below + +///////////////////////////////////////////////////////////////////// +//// //// +//// OpenCores Simple General Purpose IO core //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + + +module nsgpio + (input clk_i, input rst_i, + input cyc_i, input stb_i, input [3:0] adr_i, input we_i, input [31:0] dat_i, + output reg [31:0] dat_o, output reg ack_o, + input [31:0] atr, input [31:0] debug_0, input [31:0] debug_1, + inout [31:0] gpio + ); + + reg [63:0] ctrl; + reg [31:0] line; + reg [31:0] lgpio; // LatchedGPIO pins + reg [31:0] ddr; + + wire wb_acc = cyc_i & stb_i; // WISHBONE access + wire wb_wr = wb_acc & we_i; // WISHBONE write access + + always @(posedge clk_i or posedge rst_i) + if (rst_i) + begin + ctrl <= 64'h0; + line <= 0; + end + else if (wb_wr) + case( adr_i[3:2] ) + 2'b00 : + line <= dat_i; + 2'b01 : + ddr[31:0] <= dat_i; + 2'b10 : + ctrl[63:32] <= dat_i; + 2'b11 : + ctrl[31:0] <= dat_i; + endcase // case( adr_i[3:2] ) + + always @(posedge clk_i) + case (adr_i[3:2]) + 2'b00 : + dat_o <= lgpio; + 2'b01 : + dat_o <= ddr; + 2'b10 : + dat_o <= ctrl[63:32]; + 2'b11 : + dat_o <= ctrl[31:0]; + endcase // case(adr_i[3:2]) + + always @(posedge clk_i or posedge rst_i) + if (rst_i) + ack_o <= 1'b0; + else + ack_o <= wb_acc & !ack_o; + + // latch GPIO input pins + always @(posedge clk_i) + lgpio <= gpio; + + // assign GPIO outputs + integer n; + reg [31:0] igpio; // temporary internal signal + + always @(ctrl or line or debug_1 or debug_0 or atr or ddr) + for(n=0;n<32;n=n+1) + igpio[n] <= ddr[n] ? (ctrl[2*n+1] ? (ctrl[2*n] ? debug_1[n] : debug_0[n]) : + (ctrl[2*n] ? atr[n] : line[n]) ) + : 1'bz; + + assign gpio = igpio; + +endmodule + diff --git a/fpga/usrp2/control_lib/nsgpio16LE.v b/fpga/usrp2/control_lib/nsgpio16LE.v new file mode 100644 index 000000000..8aef0c7ae --- /dev/null +++ b/fpga/usrp2/control_lib/nsgpio16LE.v @@ -0,0 +1,123 @@ +// Modified from code originally by Richard Herveille, his copyright is below + +///////////////////////////////////////////////////////////////////// +//// //// +//// OpenCores Simple General Purpose IO core //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2002 Richard Herveille //// +//// richard@asics.ws //// +//// //// +//// This source file may be used and distributed without //// +//// restriction provided that this copyright statement is not //// +//// removed from the file and that any derivative work contains //// +//// the original copyright notice and the associated disclaimer.//// +//// //// +//// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY //// +//// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED //// +//// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS //// +//// FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE AUTHOR //// +//// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, //// +//// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES //// +//// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE //// +//// GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR //// +//// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF //// +//// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT //// +//// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT //// +//// OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE //// +//// POSSIBILITY OF SUCH DAMAGE. //// +//// //// +///////////////////////////////////////////////////////////////////// + + +module nsgpio16LE + (input clk_i, input rst_i, + input cyc_i, input stb_i, input [3:0] adr_i, input we_i, input [15:0] dat_i, + output reg [15:0] dat_o, output reg ack_o, + input [31:0] atr, input [31:0] debug_0, input [31:0] debug_1, + inout [31:0] gpio + ); + + reg [31:0] ctrl, line, ddr, dbg, lgpio; + + wire wb_acc = cyc_i & stb_i; // WISHBONE access + wire wb_wr = wb_acc & we_i; // WISHBONE write access + + always @(posedge clk_i or posedge rst_i) + if (rst_i) + begin + ctrl <= 32'h0; + line <= 32'h0; + ddr <= 32'h0; + dbg <= 32'h0; + end + else if (wb_wr) + case( adr_i[3:1] ) + 3'b000 : + line[15:0] <= dat_i; + 3'b001 : + line[31:16] <= dat_i; + 3'b010 : + ddr[15:0] <= dat_i; + 3'b011 : + ddr[31:16] <= dat_i; + 3'b100 : + ctrl[15:0] <= dat_i; + 3'b101 : + ctrl[31:16] <= dat_i; + 3'b110 : + dbg[15:0] <= dat_i; + 3'b111 : + dbg[31:16] <= dat_i; + endcase // case ( adr_i[3:1] ) + + always @(posedge clk_i) + case (adr_i[3:1]) + 3'b000 : + dat_o <= lgpio[15:0]; + 3'b001 : + dat_o <= lgpio[31:16]; + 3'b010 : + dat_o <= ddr[15:0]; + 3'b011 : + dat_o <= ddr[31:16]; + 3'b100 : + dat_o <= ctrl[15:0]; + 3'b101 : + dat_o <= ctrl[31:16]; + 3'b110 : + dat_o <= dbg[15:0]; + 3'b111 : + dat_o <= dbg[31:16]; + endcase // case (adr_i[3:1]) + + + always @(posedge clk_i or posedge rst_i) + if (rst_i) + ack_o <= 1'b0; + else + ack_o <= wb_acc & !ack_o; + + // latch GPIO input pins + always @(posedge clk_i) + lgpio <= gpio; + + // assign GPIO outputs + integer n; + reg [31:0] igpio; // temporary internal signal + + always @(ctrl or line or debug_1 or debug_0 or atr or ddr or dbg) + for(n=0;n<32;n=n+1) + igpio[n] <= ddr[n] ? (dbg[n] ? (ctrl[n] ? debug_1[n] : debug_0[n]) : + (ctrl[n] ? atr[n] : line[n]) ) + : 1'bz; + + assign gpio = igpio; + +endmodule + diff --git a/fpga/usrp2/control_lib/oneshot_2clk.v b/fpga/usrp2/control_lib/oneshot_2clk.v new file mode 100644 index 000000000..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..9c5912042 --- /dev/null +++ b/fpga/usrp2/control_lib/settings_bus_crossclock.v @@ -0,0 +1,37 @@ +// +// 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/>. +// + + + +// This module takes the settings bus on one clock domain and crosses it over to another domain +// Typically it will be used with the input settings bus on the wishbone clock, and either +// the system or dsp clock on the output side + +module settings_bus_crossclock + (input clk_i, input rst_i, input set_stb_i, input [7:0] set_addr_i, input [31:0] set_data_i, + input clk_o, input rst_o, output set_stb_o, output [7:0] set_addr_o, output [31:0] set_data_o); + + wire full, empty; + + fifo_xlnx_16x40_2clk settings_fifo + (.rst(rst_i), + .wr_clk(clk_i), .din({set_addr_i,set_data_i}), .wr_en(set_stb_i & ~full), .full(full), + .rd_clk(clk_o), .dout({set_addr_o,set_data_o}), .rd_en(~empty), .empty(empty)); + + assign set_stb_o = ~empty; + +endmodule // settings_bus_crossclock diff --git a/fpga/usrp2/control_lib/shortfifo.v b/fpga/usrp2/control_lib/shortfifo.v new file mode 100644 index 000000000..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_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/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 + |