diff options
author | Ben Hilburn <ben.hilburn@ettus.com> | 2013-10-10 10:17:27 -0700 |
---|---|---|
committer | Ben Hilburn <ben.hilburn@ettus.com> | 2013-10-10 10:17:27 -0700 |
commit | 0df4b801a34697f2058b4a7b95e08d2a0576c9db (patch) | |
tree | be10e78d1a97c037a9e7492360a178d1873b9c09 /fpga/usrp3/lib/wishbone | |
parent | 6e7bc850b66e8188718248b76b729c7cf9c89700 (diff) | |
download | uhd-0df4b801a34697f2058b4a7b95e08d2a0576c9db.tar.gz uhd-0df4b801a34697f2058b4a7b95e08d2a0576c9db.tar.bz2 uhd-0df4b801a34697f2058b4a7b95e08d2a0576c9db.zip |
Squashed B200 FPGA Source. Code from Josh Blum, Ian Buckley, and Matt Ettus.
Diffstat (limited to 'fpga/usrp3/lib/wishbone')
-rw-r--r-- | fpga/usrp3/lib/wishbone/Makefile.srcs | 19 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/axi_stream_to_wb.v | 246 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/i2c_master_bit_ctrl.v | 538 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/i2c_master_byte_ctrl.v | 344 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/i2c_master_defines.v | 64 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/i2c_master_top.v | 301 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/settings_bus.v | 46 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/settings_readback.v | 40 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/simple_uart.v | 65 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/simple_uart_rx.v | 71 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/simple_uart_tb.v | 127 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/simple_uart_tx.v | 69 | ||||
-rw-r--r-- | fpga/usrp3/lib/wishbone/wb_1master.v | 464 |
13 files changed, 2394 insertions, 0 deletions
diff --git a/fpga/usrp3/lib/wishbone/Makefile.srcs b/fpga/usrp3/lib/wishbone/Makefile.srcs new file mode 100644 index 000000000..6459de834 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/Makefile.srcs @@ -0,0 +1,19 @@ +# +# Copyright 2010-2012 Ettus Research LLC +# + +################################################## +# Wishbone Perifs +################################################## +WISHBONE_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/wishbone/, \ +simple_uart_rx.v \ +simple_uart_tx.v \ +simple_uart.v \ +wb_1master.v \ +settings_bus.v \ +settings_readback.v \ +i2c_master_top.v \ +i2c_master_bit_ctrl.v \ +i2c_master_byte_ctrl.v \ +axi_stream_to_wb.v \ +)) diff --git a/fpga/usrp3/lib/wishbone/axi_stream_to_wb.v b/fpga/usrp3/lib/wishbone/axi_stream_to_wb.v new file mode 100644 index 000000000..a71daf063 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/axi_stream_to_wb.v @@ -0,0 +1,246 @@ +// +// Copyright 2012 Ettus Research LLC +// + + +// AXI stream to/from wishbone +// Input is an axi stream which wites into a BRAM. +// Output is an axi stream which reads from a BRAM. +// This RAM can also be accessed from a wishbone interface. + +// From the wishbone interface we need to be able to: + +// Ask the module if a completed packet is available. +// Read number of bytes/lines in the BRAM. +// Release the completed packet. + +// Ask the module if an outgoing slot is available. +// Write number of bytes/lines in the BRAM. +// Release the completed packet. + +module axi_stream_to_wb +#( + parameter AWIDTH = 13, //WB addr width and buffering size in bytes + parameter UWIDTH = 4, //stream user width + parameter CTRL_ADDR = 0 //ctrl/status register +) +( + //-- the wishbone interface + input clk_i, input rst_i, + input we_i, input stb_i, input cyc_i, output reg ack_o, + input [AWIDTH-1:0] adr_i, input [31:0] dat_i, output [31:0] dat_o, + + //-- the axi stream interface input + input [63:0] rx_tdata, + input [3:0] rx_tuser, + input rx_tlast, + input rx_tvalid, + output rx_tready, + + //-- the axi stream interface output + output [63:0] tx_tdata, + output [3:0] tx_tuser, + output tx_tlast, + output tx_tvalid, + input tx_tready, + + output [31:0] debug_rx, + output [31:0] debug_tx +); + + //drive the ack signal + always @(posedge clk_i) begin + if (rst_i) ack_o <= 0; + else ack_o <= stb_i & ~ack_o; + end + + //control registers, status + reg [AWIDTH-1:0] tx_bytes, rx_bytes; + reg tx_error, rx_error; + wire rx_state_flag, tx_state_flag; + reg rx_proc_flag, tx_proc_flag; + + //assign status + wire [31:0] status; + assign status[31] = rx_state_flag; + assign status[30] = tx_state_flag; + assign status[29] = rx_error; + assign status[AWIDTH-1:0] = rx_bytes; + + // Create some piplining to break timing paths. + reg ctrl_addressed; + always @(posedge clk_i) + if (rst_i) + ctrl_addressed <= 1'b0; + else if(adr_i == CTRL_ADDR) + ctrl_addressed <= 1'b1; + else + ctrl_addressed <= 1'b0; + + //assign control + always @(posedge clk_i) begin + if (rst_i) begin + rx_proc_flag <= 0; + tx_proc_flag <= 0; + tx_error <= 0; + tx_bytes <= 0; + end + else if (we_i && ack_o && ctrl_addressed) begin + rx_proc_flag <= dat_i[31]; + tx_proc_flag <= dat_i[30]; + tx_error <= dat_i[29]; + tx_bytes <= dat_i[AWIDTH-1:0]; + end + end + + //------------------------------------------------------------------ + //-- block ram interface between wb and input stream + //------------------------------------------------------------------ + reg [AWIDTH-4:0] rx_counter; + wire [63:0] rx_bram_data64; + ram_2port #(.DWIDTH(64), .AWIDTH(AWIDTH-3)) input_stream_bram + ( + .clka(clk_i), .ena(rx_tready), .wea(rx_tvalid), + .addra(rx_counter), .dia(rx_tdata), .doa(), + .clkb(clk_i), .enb(stb_i), .web(1'b0), + .addrb(adr_i[AWIDTH-1:3]), .dib({64{1'b1}}), .dob(rx_bram_data64) + ); + + //select the data source, status, or upper/lower 32 from bram + assign dat_o = ctrl_addressed ? status : ((!adr_i[2])? rx_bram_data64[63:32]: rx_bram_data64[31:0]); + + //------------------------------------------------------------------ + //-- block ram interface between wb and output stream + //------------------------------------------------------------------ + reg [AWIDTH-4:0] tx_counter; + wire enb_out; + wire [63:0] tx_bram_data64; + ram_2port #(.DWIDTH(64), .AWIDTH(AWIDTH-3)) output_stream_bram + ( + .clka(clk_i), .ena(enb_out), .wea(1'b0), + .addra(tx_counter), .dia({64{1'b1}}), .doa(tx_tdata), + .clkb(clk_i), .enb(stb_i), .web(we_i && adr_i[2]), + .addrb(adr_i[AWIDTH-1:3]), .dib(tx_bram_data64), .dob() + ); + + //write 64 bit chunks, so register the lower write + reg [31:0] dat_i_reg; + always @(posedge clk_i) begin + if (we_i && stb_i && !adr_i[2]) dat_i_reg <= dat_i; + end + assign tx_bram_data64 = {dat_i_reg, dat_i}; + + //------------------------------------------------------------------ + //-- state machine to drive input stream + //------------------------------------------------------------------ + localparam RX_STATE_READY = 0; //waits for proc flag 0 + localparam RX_STATE_WRITE = 1; //writes stream to bram + localparam RX_STATE_RELEASE = 2; //waits for proc to flag 1 + reg [1:0] rx_state; + + always @(posedge clk_i) begin + if (rst_i) begin + rx_state <= RX_STATE_READY; + rx_counter <= 0; + rx_error <= 0; + rx_bytes <= 0; + end + else case (rx_state) + + RX_STATE_READY: begin + if (!rx_proc_flag) rx_state <= RX_STATE_WRITE; + rx_counter <= 0; + end + + RX_STATE_WRITE: begin + if (rx_tready && rx_tvalid) begin + rx_counter <= rx_counter + 1'b1; + if (rx_tlast) begin + rx_state <= RX_STATE_RELEASE; + rx_bytes <= {rx_counter + 1'b1, rx_tuser[2:0]}; + rx_error <= rx_tuser[3]; + end + end + end + + RX_STATE_RELEASE: begin + if (rx_proc_flag) rx_state <= RX_STATE_READY; + rx_counter <= 0; + end + + default: rx_state <= RX_STATE_READY; + endcase //rx_state + end + + //flag tells the processor when it can grab some input buffer + assign rx_state_flag = (rx_state == RX_STATE_RELEASE); + + //always ready to accept input data in the write state + assign rx_tready = (rx_state == RX_STATE_WRITE); + + //------------------------------------------------------------------ + //-- state machine to drive output stream + //------------------------------------------------------------------ + localparam TX_STATE_READY = 0; //waits for proc flag 0 + localparam TX_STATE_WRITE = 1; //writes bram to stream + localparam TX_STATE_RELEASE = 2; //waits for proc to flag 1 + reg [1:0] tx_state; + + always @(posedge clk_i) begin + if (rst_i) begin + tx_state <= TX_STATE_READY; + tx_counter <= 0; + end + else case (tx_state) + + TX_STATE_READY: begin + if (tx_proc_flag) begin + tx_state <= TX_STATE_WRITE; + tx_counter <= 1; + end + else tx_counter <= 0; + end + + TX_STATE_WRITE: begin + if (tx_tready && tx_tvalid) begin + tx_counter <= tx_counter + 1'b1; + if (tx_tlast) begin + tx_state <= TX_STATE_RELEASE; + end + end + end + + TX_STATE_RELEASE: begin + if (!tx_proc_flag) tx_state <= TX_STATE_READY; + tx_counter <= 0; + end + + default: tx_state <= TX_STATE_READY; + endcase //tx_state + end + + //flag tells the processor when it can grab available out buffer + assign tx_state_flag = (tx_state == TX_STATE_READY); + + //the output user bus assignment (non-zero only at end) + assign tx_tuser = (tx_tlast)? {tx_error, tx_bytes[2:0]} : 4'b0; + + //end of frame signal + assign tx_tlast = (tx_counter == tx_bytes[AWIDTH-1:3]); + + //output is always valid in state write + assign tx_tvalid = (tx_state == TX_STATE_WRITE); + + //enable the read so we can pre-read due to read 1 cycle delay + assign enb_out = (tx_state == TX_STATE_WRITE)? (tx_tvalid && tx_tready) : 1'b1; + + assign debug_rx = { + rx_state, rx_tlast, rx_tvalid, rx_tready, rx_tuser[2:0], //8 + rx_proc_flag, rx_state_flag, rx_tdata[21:0] //24 + }; + assign debug_tx = { + tx_state, tx_tlast, tx_tvalid, tx_tready, tx_tuser[2:0], //8 + tx_proc_flag, tx_state_flag, tx_tdata[21:0] //24 + }; + +endmodule //axi_stream_to_wb diff --git a/fpga/usrp3/lib/wishbone/i2c_master_bit_ctrl.v b/fpga/usrp3/lib/wishbone/i2c_master_bit_ctrl.v new file mode 100644 index 000000000..68ec27004 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/i2c_master_bit_ctrl.v @@ -0,0 +1,538 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master bit-controller //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_bit_ctrl.v,v 1.12 2006/09/04 09:08:13 rherveille Exp $ +// +// $Date: 2006/09/04 09:08:13 $ +// $Revision: 1.12 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_bit_ctrl.v,v $ +// Revision 1.12 2006/09/04 09:08:13 rherveille +// fixed short scl high pulse after clock stretch +// fixed slave model not returning correct '(n)ack' signal +// +// Revision 1.11 2004/05/07 11:02:26 rherveille +// Fixed a bug where the core would signal an arbitration lost (AL bit set), when another master controls the bus and the other master generates a STOP bit. +// +// Revision 1.10 2003/08/09 07:01:33 rherveille +// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +// Fixed a potential bug in the byte controller's host-acknowledge generation. +// +// Revision 1.9 2003/03/10 14:26:37 rherveille +// Fixed cmd_ack generation item (no bug). +// +// Revision 1.8 2003/02/05 00:06:10 rherveille +// Fixed a bug where the core would trigger an erroneous 'arbitration lost' interrupt after being reset, when the reset pulse width < 3 clk cycles. +// +// Revision 1.7 2002/12/26 16:05:12 rherveille +// Small code simplifications +// +// Revision 1.6 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.5 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.4 2002/10/30 18:10:07 rherveille +// Fixed some reported minor start/stop generation timing issuess. +// +// Revision 1.3 2002/06/15 07:37:03 rherveille +// Fixed a small timing bug in the bit controller.\nAdded verilog simulation environment. +// +// Revision 1.2 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + +// +///////////////////////////////////// +// Bit controller section +///////////////////////////////////// +// +// Translate simple commands into SCL/SDA transitions +// Each command has 5 states, A/B/C/D/idle +// +// start: SCL ~~~~~~~~~~\____ +// SDA ~~~~~~~~\______ +// x | A | B | C | D | i +// +// repstart SCL ____/~~~~\___ +// SDA __/~~~\______ +// x | A | B | C | D | i +// +// stop SCL ____/~~~~~~~~ +// SDA ==\____/~~~~~ +// x | A | B | C | D | i +// +//- write SCL ____/~~~~\____ +// SDA ==X=========X= +// x | A | B | C | D | i +// +//- read SCL ____/~~~~\____ +// SDA XXXX=====XXXX +// x | A | B | C | D | i +// + +// Timing: Normal mode Fast mode +/////////////////////////////////////////////////////////////////////// +// Fscl 100KHz 400KHz +// Th_scl 4.0us 0.6us High period of SCL +// Tl_scl 4.7us 1.3us Low period of SCL +// Tsu:sta 4.7us 0.6us setup time for a repeated start condition +// Tsu:sto 4.0us 0.6us setup time for a stop conditon +// Tbuf 4.7us 1.3us Bus free time between a stop and start condition +// + +// synopsys translate_off +//`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_bit_ctrl( + clk, rst, nReset, + clk_cnt, ena, cmd, cmd_ack, busy, al, din, dout, + scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen + ); + + // + // inputs & outputs + // + input clk; + input rst; + input nReset; + input ena; // core enable signal + + input [15:0] clk_cnt; // clock prescale value + + input [3:0] cmd; + output cmd_ack; // command complete acknowledge + reg cmd_ack; + output busy; // i2c bus busy + reg busy; + output al; // i2c bus arbitration lost + reg al; + + input din; + output dout; + reg dout; + + // I2C lines + input scl_i; // i2c clock line input + output scl_o; // i2c clock line output + output scl_oen; // i2c clock line output enable (active low) + reg scl_oen; + input sda_i; // i2c data line input + output sda_o; // i2c data line output + output sda_oen; // i2c data line output enable (active low) + reg sda_oen; + + + // + // variable declarations + // + + reg sSCL, sSDA; // synchronized SCL and SDA inputs + reg dscl_oen; // delayed scl_oen + reg sda_chk; // check SDA output (Multi-master arbitration) + reg clk_en; // clock generation signals + wire slave_wait; +// reg [15:0] cnt = clk_cnt; // clock divider counter (simulation) + reg [15:0] cnt; // clock divider counter (synthesis) + + // state machine variable + reg [16:0] c_state; // synopsys enum_state + + // + // module body + // + + // whenever the slave is not ready it can delay the cycle by pulling SCL low + // delay scl_oen + always @(posedge clk) + dscl_oen <= #1 scl_oen; + + assign slave_wait = dscl_oen && !sSCL; + + + // generate clk enable signal + always @(posedge clk or negedge nReset) + if(~nReset) + begin + cnt <= #1 16'h0; + clk_en <= #1 1'b1; + end + else if (rst) + begin + cnt <= #1 16'h0; + clk_en <= #1 1'b1; + end + else if ( ~|cnt || !ena) + begin + cnt <= #1 clk_cnt; + clk_en <= #1 1'b1; + end + else if (slave_wait) + begin + cnt <= #1 cnt; + clk_en <= #1 1'b0; + end + else + begin + cnt <= #1 cnt - 16'h1; + clk_en <= #1 1'b0; + end + + + // generate bus status controller + reg dSCL, dSDA; + reg sta_condition; + reg sto_condition; + + // synchronize SCL and SDA inputs + // reduce metastability risc + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sSCL <= #1 1'b1; + sSDA <= #1 1'b1; + + dSCL <= #1 1'b1; + dSDA <= #1 1'b1; + end + else if (rst) + begin + sSCL <= #1 1'b1; + sSDA <= #1 1'b1; + + dSCL <= #1 1'b1; + dSDA <= #1 1'b1; + end + else + begin + sSCL <= #1 scl_i; + sSDA <= #1 sda_i; + + dSCL <= #1 sSCL; + dSDA <= #1 sSDA; + end + + // detect start condition => detect falling edge on SDA while SCL is high + // detect stop condition => detect rising edge on SDA while SCL is high + always @(posedge clk or negedge nReset) + if (~nReset) + begin + sta_condition <= #1 1'b0; + sto_condition <= #1 1'b0; + end + else if (rst) + begin + sta_condition <= #1 1'b0; + sto_condition <= #1 1'b0; + end + else + begin + sta_condition <= #1 ~sSDA & dSDA & sSCL; + sto_condition <= #1 sSDA & ~dSDA & sSCL; + end + + // generate i2c bus busy signal + always @(posedge clk or negedge nReset) + if(!nReset) + busy <= #1 1'b0; + else if (rst) + busy <= #1 1'b0; + else + busy <= #1 (sta_condition | busy) & ~sto_condition; + + // generate arbitration lost signal + // aribitration lost when: + // 1) master drives SDA high, but the i2c bus is low + // 2) stop detected while not requested + reg cmd_stop; + always @(posedge clk or negedge nReset) + if (~nReset) + cmd_stop <= #1 1'b0; + else if (rst) + cmd_stop <= #1 1'b0; + else if (clk_en) + cmd_stop <= #1 cmd == `I2C_CMD_STOP; + + always @(posedge clk or negedge nReset) + if (~nReset) + al <= #1 1'b0; + else if (rst) + al <= #1 1'b0; + else + al <= #1 (sda_chk & ~sSDA & sda_oen) | (|c_state & sto_condition & ~cmd_stop); + + + // generate dout signal (store SDA on rising edge of SCL) + always @(posedge clk) + if(sSCL & ~dSCL) + dout <= #1 sSDA; + + // generate statemachine + + // nxt_state decoder + parameter [16:0] idle = 17'b0_0000_0000_0000_0000; + parameter [16:0] start_a = 17'b0_0000_0000_0000_0001; + parameter [16:0] start_b = 17'b0_0000_0000_0000_0010; + parameter [16:0] start_c = 17'b0_0000_0000_0000_0100; + parameter [16:0] start_d = 17'b0_0000_0000_0000_1000; + parameter [16:0] start_e = 17'b0_0000_0000_0001_0000; + parameter [16:0] stop_a = 17'b0_0000_0000_0010_0000; + parameter [16:0] stop_b = 17'b0_0000_0000_0100_0000; + parameter [16:0] stop_c = 17'b0_0000_0000_1000_0000; + parameter [16:0] stop_d = 17'b0_0000_0001_0000_0000; + parameter [16:0] rd_a = 17'b0_0000_0010_0000_0000; + parameter [16:0] rd_b = 17'b0_0000_0100_0000_0000; + parameter [16:0] rd_c = 17'b0_0000_1000_0000_0000; + parameter [16:0] rd_d = 17'b0_0001_0000_0000_0000; + parameter [16:0] wr_a = 17'b0_0010_0000_0000_0000; + parameter [16:0] wr_b = 17'b0_0100_0000_0000_0000; + parameter [16:0] wr_c = 17'b0_1000_0000_0000_0000; + parameter [16:0] wr_d = 17'b1_0000_0000_0000_0000; + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b0; + scl_oen <= #1 1'b1; + sda_oen <= #1 1'b1; + sda_chk <= #1 1'b0; + end + else if (rst | al) + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b0; + scl_oen <= #1 1'b1; + sda_oen <= #1 1'b1; + sda_chk <= #1 1'b0; + end + else + begin + cmd_ack <= #1 1'b0; // default no command acknowledge + assert cmd_ack only 1clk cycle + + if (clk_en) + case (c_state) // synopsys full_case parallel_case + // idle state + idle: + begin + case (cmd) // synopsys full_case parallel_case + `I2C_CMD_START: + c_state <= #1 start_a; + + `I2C_CMD_STOP: + c_state <= #1 stop_a; + + `I2C_CMD_WRITE: + c_state <= #1 wr_a; + + `I2C_CMD_READ: + c_state <= #1 rd_a; + + default: + c_state <= #1 idle; + endcase + + scl_oen <= #1 scl_oen; // keep SCL in same state + sda_oen <= #1 sda_oen; // keep SDA in same state + sda_chk <= #1 1'b0; // don't check SDA output + end + + // start + start_a: + begin + c_state <= #1 start_b; + scl_oen <= #1 scl_oen; // keep SCL in same state + sda_oen <= #1 1'b1; // set SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_b: + begin + c_state <= #1 start_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b1; // keep SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_c: + begin + c_state <= #1 start_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // set SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_d: + begin + c_state <= #1 start_e; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + start_e: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + // stop + stop_a: + begin + c_state <= #1 stop_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 1'b0; // set SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_b: + begin + c_state <= #1 stop_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_c: + begin + c_state <= #1 stop_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b0; // keep SDA low + sda_chk <= #1 1'b0; // don't check SDA output + end + + stop_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b1; // set SDA high + sda_chk <= #1 1'b0; // don't check SDA output + end + + // read + rd_a: + begin + c_state <= #1 rd_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 1'b1; // tri-state SDA + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_b: + begin + c_state <= #1 rd_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_c: + begin + c_state <= #1 rd_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + rd_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 1'b1; // keep SDA tri-stated + sda_chk <= #1 1'b0; // don't check SDA output + end + + // write + wr_a: + begin + c_state <= #1 wr_b; + scl_oen <= #1 1'b0; // keep SCL low + sda_oen <= #1 din; // set SDA + sda_chk <= #1 1'b0; // don't check SDA output (SCL low) + end + + wr_b: + begin + c_state <= #1 wr_c; + scl_oen <= #1 1'b1; // set SCL high + sda_oen <= #1 din; // keep SDA + sda_chk <= #1 1'b1; // check SDA output + end + + wr_c: + begin + c_state <= #1 wr_d; + scl_oen <= #1 1'b1; // keep SCL high + sda_oen <= #1 din; + sda_chk <= #1 1'b1; // check SDA output + end + + wr_d: + begin + c_state <= #1 idle; + cmd_ack <= #1 1'b1; + scl_oen <= #1 1'b0; // set SCL low + sda_oen <= #1 din; + sda_chk <= #1 1'b0; // don't check SDA output (SCL low) + end + + endcase + end + + + // assign scl and sda output (always gnd) + assign scl_o = 1'b0; + assign sda_o = 1'b0; + +endmodule diff --git a/fpga/usrp3/lib/wishbone/i2c_master_byte_ctrl.v b/fpga/usrp3/lib/wishbone/i2c_master_byte_ctrl.v new file mode 100644 index 000000000..784b58188 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/i2c_master_byte_ctrl.v @@ -0,0 +1,344 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master byte-controller //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_byte_ctrl.v,v 1.7 2004/02/18 11:40:46 rherveille Exp $ +// +// $Date: 2004/02/18 11:40:46 $ +// $Revision: 1.7 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_byte_ctrl.v,v $ +// Revision 1.7 2004/02/18 11:40:46 rherveille +// Fixed a potential bug in the statemachine. During a 'stop' 2 cmd_ack signals were generated. Possibly canceling a new start command. +// +// Revision 1.6 2003/08/09 07:01:33 rherveille +// Fixed a bug in the Arbitration Lost generation caused by delay on the (external) sda line. +// Fixed a potential bug in the byte controller's host-acknowledge generation. +// +// Revision 1.5 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.4 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.3 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + +// synopsys translate_off +//`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_byte_ctrl ( + clk, rst, nReset, ena, clk_cnt, start, stop, read, write, ack_in, din, + cmd_ack, ack_out, dout, i2c_busy, i2c_al, scl_i, scl_o, scl_oen, sda_i, sda_o, sda_oen ); + + // + // inputs & outputs + // + input clk; // master clock + input rst; // synchronous active high reset + input nReset; // asynchronous active low reset + input ena; // core enable signal + + input [15:0] clk_cnt; // 4x SCL + + // control inputs + input start; + input stop; + input read; + input write; + input ack_in; + input [7:0] din; + + // status outputs + output cmd_ack; + reg cmd_ack; + output ack_out; + reg ack_out; + output i2c_busy; + output i2c_al; + output [7:0] dout; + + // I2C signals + input scl_i; + output scl_o; + output scl_oen; + input sda_i; + output sda_o; + output sda_oen; + + + // + // Variable declarations + // + + // statemachine + parameter [4:0] ST_IDLE = 5'b0_0000; + parameter [4:0] ST_START = 5'b0_0001; + parameter [4:0] ST_READ = 5'b0_0010; + parameter [4:0] ST_WRITE = 5'b0_0100; + parameter [4:0] ST_ACK = 5'b0_1000; + parameter [4:0] ST_STOP = 5'b1_0000; + + // signals for bit_controller + reg [3:0] core_cmd; + reg core_txd; + wire core_ack, core_rxd; + + // signals for shift register + reg [7:0] sr; //8bit shift register + reg shift, ld; + + // signals for state machine + wire go; + reg [2:0] dcnt; + wire cnt_done; + + // + // Module body + // + + // hookup bit_controller + i2c_master_bit_ctrl bit_controller ( + .clk ( clk ), + .rst ( rst ), + .nReset ( nReset ), + .ena ( ena ), + .clk_cnt ( clk_cnt ), + .cmd ( core_cmd ), + .cmd_ack ( core_ack ), + .busy ( i2c_busy ), + .al ( i2c_al ), + .din ( core_txd ), + .dout ( core_rxd ), + .scl_i ( scl_i ), + .scl_o ( scl_o ), + .scl_oen ( scl_oen ), + .sda_i ( sda_i ), + .sda_o ( sda_o ), + .sda_oen ( sda_oen ) + ); + + // generate go-signal + assign go = (read | write | stop) & ~cmd_ack; + + // assign dout output to shift-register + assign dout = sr; + + // generate shift register + always @(posedge clk or negedge nReset) + if (!nReset) + sr <= #1 8'h0; + else if (rst) + sr <= #1 8'h0; + else if (ld) + sr <= #1 din; + else if (shift) + sr <= #1 {sr[6:0], core_rxd}; + + // generate counter + always @(posedge clk or negedge nReset) + if (!nReset) + dcnt <= #1 3'h0; + else if (rst) + dcnt <= #1 3'h0; + else if (ld) + dcnt <= #1 3'h7; + else if (shift) + dcnt <= #1 dcnt - 3'h1; + + assign cnt_done = ~(|dcnt); + + // + // state machine + // + reg [4:0] c_state; // synopsis enum_state + + always @(posedge clk or negedge nReset) + if (!nReset) + begin + core_cmd <= #1 `I2C_CMD_NOP; + core_txd <= #1 1'b0; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + c_state <= #1 ST_IDLE; + ack_out <= #1 1'b0; + end + else if (rst | i2c_al) + begin + core_cmd <= #1 `I2C_CMD_NOP; + core_txd <= #1 1'b0; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + c_state <= #1 ST_IDLE; + ack_out <= #1 1'b0; + end + else + begin + // initially reset all signals + core_txd <= #1 sr[7]; + shift <= #1 1'b0; + ld <= #1 1'b0; + cmd_ack <= #1 1'b0; + + case (c_state) // synopsys full_case parallel_case + ST_IDLE: + if (go) + begin + if (start) + begin + c_state <= #1 ST_START; + core_cmd <= #1 `I2C_CMD_START; + end + else if (read) + begin + c_state <= #1 ST_READ; + core_cmd <= #1 `I2C_CMD_READ; + end + else if (write) + begin + c_state <= #1 ST_WRITE; + core_cmd <= #1 `I2C_CMD_WRITE; + end + else // stop + begin + c_state <= #1 ST_STOP; + core_cmd <= #1 `I2C_CMD_STOP; + end + + ld <= #1 1'b1; + end + + ST_START: + if (core_ack) + begin + if (read) + begin + c_state <= #1 ST_READ; + core_cmd <= #1 `I2C_CMD_READ; + end + else + begin + c_state <= #1 ST_WRITE; + core_cmd <= #1 `I2C_CMD_WRITE; + end + + ld <= #1 1'b1; + end + + ST_WRITE: + if (core_ack) + if (cnt_done) + begin + c_state <= #1 ST_ACK; + core_cmd <= #1 `I2C_CMD_READ; + end + else + begin + c_state <= #1 ST_WRITE; // stay in same state + core_cmd <= #1 `I2C_CMD_WRITE; // write next bit + shift <= #1 1'b1; + end + + ST_READ: + if (core_ack) + begin + if (cnt_done) + begin + c_state <= #1 ST_ACK; + core_cmd <= #1 `I2C_CMD_WRITE; + end + else + begin + c_state <= #1 ST_READ; // stay in same state + core_cmd <= #1 `I2C_CMD_READ; // read next bit + end + + shift <= #1 1'b1; + core_txd <= #1 ack_in; + end + + ST_ACK: + if (core_ack) + begin + if (stop) + begin + c_state <= #1 ST_STOP; + core_cmd <= #1 `I2C_CMD_STOP; + end + else + begin + c_state <= #1 ST_IDLE; + core_cmd <= #1 `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= #1 1'b1; + end + + // assign ack_out output to bit_controller_rxd (contains last received bit) + ack_out <= #1 core_rxd; + + core_txd <= #1 1'b1; + end + else + core_txd <= #1 ack_in; + + ST_STOP: + if (core_ack) + begin + c_state <= #1 ST_IDLE; + core_cmd <= #1 `I2C_CMD_NOP; + + // generate command acknowledge signal + cmd_ack <= #1 1'b1; + end + + endcase + end +endmodule diff --git a/fpga/usrp3/lib/wishbone/i2c_master_defines.v b/fpga/usrp3/lib/wishbone/i2c_master_defines.v new file mode 100644 index 000000000..ee3b694fa --- /dev/null +++ b/fpga/usrp3/lib/wishbone/i2c_master_defines.v @@ -0,0 +1,64 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE rev.B2 compliant I2C Master controller defines //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_defines.v,v 1.3 2001/11/05 11:59:25 rherveille Exp $ +// +// $Date: 2001/11/05 11:59:25 $ +// $Revision: 1.3 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_defines.v,v $ +// Revision 1.3 2001/11/05 11:59:25 rherveille +// Fixed wb_ack_o generation bug. +// Fixed bug in the byte_controller statemachine. +// Added headers. +// + + +// I2C registers wishbone addresses + +// bitcontroller states +`define I2C_CMD_NOP 4'b0000 +`define I2C_CMD_START 4'b0001 +`define I2C_CMD_STOP 4'b0010 +`define I2C_CMD_WRITE 4'b0100 +`define I2C_CMD_READ 4'b1000 diff --git a/fpga/usrp3/lib/wishbone/i2c_master_top.v b/fpga/usrp3/lib/wishbone/i2c_master_top.v new file mode 100644 index 000000000..be1fcfe55 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/i2c_master_top.v @@ -0,0 +1,301 @@ +///////////////////////////////////////////////////////////////////// +//// //// +//// WISHBONE revB.2 compliant I2C Master controller Top-level //// +//// //// +//// //// +//// Author: Richard Herveille //// +//// richard@asics.ws //// +//// www.asics.ws //// +//// //// +//// Downloaded from: http://www.opencores.org/projects/i2c/ //// +//// //// +///////////////////////////////////////////////////////////////////// +//// //// +//// Copyright (C) 2001 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. //// +//// //// +///////////////////////////////////////////////////////////////////// + +// CVS Log +// +// $Id: i2c_master_top.v,v 1.11 2005/02/27 09:26:24 rherveille Exp $ +// +// $Date: 2005/02/27 09:26:24 $ +// $Revision: 1.11 $ +// $Author: rherveille $ +// $Locker: $ +// $State: Exp $ +// +// Change History: +// $Log: i2c_master_top.v,v $ +// Revision 1.11 2005/02/27 09:26:24 rherveille +// Fixed register overwrite issue. +// Removed full_case pragma, replaced it by a default statement. +// +// Revision 1.10 2003/09/01 10:34:38 rherveille +// Fix a blocking vs. non-blocking error in the wb_dat output mux. +// +// Revision 1.9 2003/01/09 16:44:45 rherveille +// Fixed a bug in the Command Register declaration. +// +// Revision 1.8 2002/12/26 16:05:12 rherveille +// Small code simplifications +// +// Revision 1.7 2002/12/26 15:02:32 rherveille +// Core is now a Multimaster I2C controller +// +// Revision 1.6 2002/11/30 22:24:40 rherveille +// Cleaned up code +// +// Revision 1.5 2001/11/10 10:52:55 rherveille +// Changed PRER reset value from 0x0000 to 0xffff, conform specs. +// + +// synopsys translate_off +//`include "timescale.v" +// synopsys translate_on + +`include "i2c_master_defines.v" + +module i2c_master_top( + wb_clk_i, wb_rst_i, arst_i, wb_adr_i, wb_dat_i, wb_dat_o, + wb_we_i, wb_stb_i, wb_cyc_i, wb_ack_o, wb_inta_o, + scl_pad_i, scl_pad_o, scl_padoen_o, sda_pad_i, sda_pad_o, sda_padoen_o ); + + // parameters + parameter ARST_LVL = 1'b0; // asynchronous reset level + + // + // inputs & outputs + // + + // wishbone signals + input wb_clk_i; // master clock input + input wb_rst_i; // synchronous active high reset + input arst_i; // asynchronous reset + input [2:0] wb_adr_i; // lower address bits + input [7:0] wb_dat_i; // databus input + output [7:0] wb_dat_o; // databus output + input wb_we_i; // write enable input + input wb_stb_i; // stobe/core select signal + input wb_cyc_i; // valid bus cycle input + output wb_ack_o; // bus cycle acknowledge output + output wb_inta_o; // interrupt request signal output + + reg [7:0] wb_dat_o; + reg wb_ack_o; + reg wb_inta_o; + + // I2C signals + // i2c clock line + input scl_pad_i; // SCL-line input + output scl_pad_o; // SCL-line output (always 1'b0) + output scl_padoen_o; // SCL-line output enable (active low) + + // i2c data line + input sda_pad_i; // SDA-line input + output sda_pad_o; // SDA-line output (always 1'b0) + output sda_padoen_o; // SDA-line output enable (active low) + + + // + // variable declarations + // + + // registers + reg [15:0] prer; // clock prescale register + reg [ 7:0] ctr; // control register + reg [ 7:0] txr; // transmit register + wire [ 7:0] rxr; // receive register + reg [ 7:0] cr; // command register + wire [ 7:0] sr; // status register + + // done signal: command completed, clear command register + wire done; + + // core enable signal + wire core_en; + wire ien; + + // status register signals + wire irxack; + reg rxack; // received aknowledge from slave + reg tip; // transfer in progress + reg irq_flag; // interrupt pending flag + wire i2c_busy; // bus busy (start signal detected) + wire i2c_al; // i2c bus arbitration lost + reg al; // status register arbitration lost bit + + // + // module body + // + + // generate internal reset + wire rst_i = arst_i ^ ARST_LVL; + + // generate wishbone signals + wire wb_wacc = wb_cyc_i & wb_stb_i & wb_we_i; + + // generate acknowledge output signal + always @(posedge wb_clk_i) + wb_ack_o <= #1 wb_cyc_i & wb_stb_i & ~wb_ack_o; // because timing is always honored + + // assign DAT_O + always @(posedge wb_clk_i) + begin + case (wb_adr_i) // synopsis parallel_case + 3'b000: wb_dat_o <= #1 prer[ 7:0]; + 3'b001: wb_dat_o <= #1 prer[15:8]; + 3'b010: wb_dat_o <= #1 ctr; + 3'b011: wb_dat_o <= #1 rxr; // write is transmit register (txr) + 3'b100: wb_dat_o <= #1 sr; // write is command register (cr) + 3'b101: wb_dat_o <= #1 txr; + 3'b110: wb_dat_o <= #1 cr; + 3'b111: wb_dat_o <= #1 0; // reserved + endcase + end + + // generate registers + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + begin + prer <= #1 16'hffff; + ctr <= #1 8'h0; + txr <= #1 8'h0; + end + else if (wb_rst_i) + begin + prer <= #1 16'hffff; + ctr <= #1 8'h0; + txr <= #1 8'h0; + end + else + if (wb_wacc) + case (wb_adr_i) // synopsis parallel_case + 3'b000 : prer [ 7:0] <= #1 wb_dat_i; + 3'b001 : prer [15:8] <= #1 wb_dat_i; + 3'b010 : ctr <= #1 wb_dat_i; + 3'b011 : txr <= #1 wb_dat_i; + default: ; + endcase + + // generate command register (special case) + always @(posedge wb_clk_i or negedge rst_i) + if (~rst_i) + cr <= #1 8'h0; + else if (wb_rst_i) + cr <= #1 8'h0; + else if (wb_wacc) + begin + if (core_en & (wb_adr_i == 3'b100) ) + cr <= #1 wb_dat_i; + end + else + begin + if (done | i2c_al) + cr[7:4] <= #1 4'h0; // clear command bits when done + // or when aribitration lost + cr[2:1] <= #1 2'b0; // reserved bits + cr[0] <= #1 2'b0; // clear IRQ_ACK bit + end + + + // decode command register + wire sta = cr[7]; + wire sto = cr[6]; + wire rd = cr[5]; + wire wr = cr[4]; + wire ack = cr[3]; + wire iack = cr[0]; + + // decode control register + assign core_en = ctr[7]; + assign ien = ctr[6]; + + // hookup byte controller block + i2c_master_byte_ctrl byte_controller ( + .clk ( wb_clk_i ), + .rst ( wb_rst_i ), + .nReset ( rst_i ), + .ena ( core_en ), + .clk_cnt ( prer ), + .start ( sta ), + .stop ( sto ), + .read ( rd ), + .write ( wr ), + .ack_in ( ack ), + .din ( txr ), + .cmd_ack ( done ), + .ack_out ( irxack ), + .dout ( rxr ), + .i2c_busy ( i2c_busy ), + .i2c_al ( i2c_al ), + .scl_i ( scl_pad_i ), + .scl_o ( scl_pad_o ), + .scl_oen ( scl_padoen_o ), + .sda_i ( sda_pad_i ), + .sda_o ( sda_pad_o ), + .sda_oen ( sda_padoen_o ) + ); + + // status register block + interrupt request signal + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + begin + al <= #1 1'b0; + rxack <= #1 1'b0; + tip <= #1 1'b0; + irq_flag <= #1 1'b0; + end + else if (wb_rst_i) + begin + al <= #1 1'b0; + rxack <= #1 1'b0; + tip <= #1 1'b0; + irq_flag <= #1 1'b0; + end + else + begin + al <= #1 i2c_al | (al & ~sta); + rxack <= #1 irxack; + tip <= #1 (rd | wr); + irq_flag <= #1 (done | i2c_al | irq_flag) & ~iack; // interrupt request flag is always generated + end + + // generate interrupt request signals + always @(posedge wb_clk_i or negedge rst_i) + if (!rst_i) + wb_inta_o <= #1 1'b0; + else if (wb_rst_i) + wb_inta_o <= #1 1'b0; + else + wb_inta_o <= #1 irq_flag && ien; // interrupt signal is only generated when IEN (interrupt enable bit is set) + + // assign status register bits + assign sr[7] = rxack; + assign sr[6] = i2c_busy; + assign sr[5] = al; + assign sr[4:2] = 3'h0; // reserved + assign sr[1] = tip; + assign sr[0] = irq_flag; + +endmodule diff --git a/fpga/usrp3/lib/wishbone/settings_bus.v b/fpga/usrp3/lib/wishbone/settings_bus.v new file mode 100644 index 000000000..39f148916 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/settings_bus.v @@ -0,0 +1,46 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// + + + +// 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, parameter SWIDTH=8) + (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 [SWIDTH-1: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 <= {SWIDTH{1'b0}}; + data <= 32'd0; + end + else if(wb_we_i & wb_stb_i & ~wb_ack_o) + begin + strobe <= 1'b1; + addr <= wb_adr_i[SWIDTH+1: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/usrp3/lib/wishbone/settings_readback.v b/fpga/usrp3/lib/wishbone/settings_readback.v new file mode 100644 index 000000000..745571717 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/settings_readback.v @@ -0,0 +1,40 @@ +// +// Copyright 2011-2012 Ettus Research LLC +// + + +// +// Use this module in conjunction with settings_bus.v to add stateful reads +// to the settings bis. This enables you to do things like have registers reset atomicly +// as they are read. It also pipelines the address path to ease timing. +// + +module settings_readback + #(parameter AWIDTH=16, parameter DWIDTH=32, parameter RB_ADDRW=2) + ( + input wb_clk, + input wb_rst, + input [AWIDTH-1:0] wb_adr_i, + input wb_stb_i, + input wb_we_i, + input [DWIDTH-1:0] rb_data, + output reg [RB_ADDRW-1:0] rb_addr, + output [DWIDTH-1:0] wb_dat_o, + output reg rb_rd_stb + ); + + always @(posedge wb_clk) + if (wb_stb_i && ~wb_we_i) begin + rb_addr <= wb_adr_i[RB_ADDRW+1:2]; + rb_rd_stb <= 1'b1; + end else begin + rb_rd_stb <= 1'b0; + end + + assign wb_dat_o = rb_data; + + + +endmodule // settings_readback + +
\ No newline at end of file diff --git a/fpga/usrp3/lib/wishbone/simple_uart.v b/fpga/usrp3/lib/wishbone/simple_uart.v new file mode 100644 index 000000000..51dc23f16 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/simple_uart.v @@ -0,0 +1,65 @@ +// +// Copyright 2011 Ettus Research LLC +// + + + +module simple_uart + #(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 [5: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 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 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/usrp3/lib/wishbone/simple_uart_rx.v b/fpga/usrp3/lib/wishbone/simple_uart_rx.v new file mode 100644 index 000000000..7790a0a87 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/simple_uart_rx.v @@ -0,0 +1,71 @@ +// +// Copyright 2011-2013 Ettus Research LLC +// + + + + +module simple_uart_rx + #(parameter SIZE=0) + (input clk, input rst, + output [7:0] fifo_out, input fifo_read, output [5: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 i_tready, o_tvalid; + wire full = ~i_tready; + wire write = ~full & rx_d2 & stop_now; + assign fifo_empty = ~o_tvalid; + + axi_fifo #(.WIDTH(8), .SIZE(SIZE)) fifo + (.clk(clk),.reset(rst), .clear(1'b0), + .i_tdata(sr),.i_tvalid(write),.i_tready(i_tready), + .o_tdata(fifo_out),.o_tvalid(o_tvalid),.o_tready(fifo_read), + .space(),.occupied(fifo_level) ); + +endmodule // simple_uart_rx diff --git a/fpga/usrp3/lib/wishbone/simple_uart_tb.v b/fpga/usrp3/lib/wishbone/simple_uart_tb.v new file mode 100644 index 000000000..8b1427f99 --- /dev/null +++ b/fpga/usrp3/lib/wishbone/simple_uart_tb.v @@ -0,0 +1,127 @@ +module simple_uart_tb(); + + localparam SUART_CLKDIV = 0; + localparam SUART_TXLEVEL = 1; + localparam SUART_RXLEVEL = 2; + localparam SUART_TXCHAR = 3; + localparam SUART_RXCHAR = 4; + + reg clk; + reg rst; + + reg we_i; + reg stb_i; + reg cyc_i; + wire ack_o; + reg [2:0] adr_i; + reg [31:0] dat_i; + wire [31:0] dat_o; + wire rx_int_o; + wire tx_int_o; + wire tx_o; + reg rx_i; + wire baud_o; + + reg [31:0] read_data; + + + initial + clk = 0; + + // 200MHz clock + always + #2.5 clk = ~clk; + + initial begin + rst <= 0; + we_i <= 0; + stb_i <= 0; + cyc_i <= 0; + adr_i <= 0; + dat_i <= 0; + rx_i <= 0; + end + + + task write_wb; + input [31:0] data_in; + input [2:0] addr_in; + + begin + @(negedge clk); + dat_i <= data_in; + adr_i <= addr_in; + we_i <= 1; + stb_i <= 1; + cyc_i <= 1; + @(negedge clk); + while (ack_o == 0) begin + @(negedge clk); + end + dat_i <= 0; + adr_i <= 0; + we_i <= 0; + stb_i <= 0; + cyc_i <= 0; + end + endtask // write_wb + + + task read_wb; + output [31:0] data_out; + input [2:0] addr_in; + + begin + @(negedge clk); + adr_i <= addr_in; + we_i <= 0; + stb_i <= 1; + cyc_i <= 1; + @(negedge clk); + while (ack_o == 0) begin + @(negedge clk); + end + data_out <= dat_o; + adr_i <= 0; + stb_i <= 0; + cyc_i <= 0; + end + endtask // write_wb + + initial begin + @(negedge clk); + rst <= 1; + repeat(10) @(negedge clk); + rst <= 0; + repeat(10) @(negedge clk); + write_wb(4'h0620,SUART_CLKDIV); + repeat(10) @(negedge clk); + read_wb(read_data,SUART_TXLEVEL); + repeat(10) @(negedge clk); + end // initial begin + + + + simple_uart + #(.CLKDIV_DEFAULT(16'd0)) + simple_uart_i + ( + .clk_i(clk), + .rst_i(rst), + .we_i(we_i), + .stb_i(stb_i), + .cyc_i(cyc_i), + .ack_o(ack_o), + .adr_i(adr_i), + .dat_i(dat_i), + .dat_o(dat_o), + .rx_int_o(rx_int_o), + .tx_int_o(tx_int_o), + .tx_o(tx_o), + .rx_i(rx_i), + .baud_o(baud_o) + ); + + + +endmodule // simple_uart_tb diff --git a/fpga/usrp3/lib/wishbone/simple_uart_tx.v b/fpga/usrp3/lib/wishbone/simple_uart_tx.v new file mode 100644 index 000000000..3eb1a1ecd --- /dev/null +++ b/fpga/usrp3/lib/wishbone/simple_uart_tx.v @@ -0,0 +1,69 @@ +// +// Copyright 2011-2013 Ettus Research LLC +// + + + +module simple_uart_tx + #(parameter SIZE=0) + (input clk, input rst, + input [7:0] fifo_in, input fifo_write, output [5: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; + wire i_tready, o_tvalid; + + assign fifo_full = ~i_tready; + assign empty = ~o_tvalid; + + axi_fifo #(.WIDTH(8), .SIZE(SIZE)) fifo + (.clk(clk),.reset(rst), .clear(1'b0), + .i_tdata(fifo_in), .i_tvalid(fifo_write), .i_tready(i_tready), + .o_tdata(char_to_send),.o_tvalid(o_tvalid),.o_tready(read), + .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 == 10) + 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/usrp3/lib/wishbone/wb_1master.v b/fpga/usrp3/lib/wishbone/wb_1master.v new file mode 100644 index 000000000..fb313efae --- /dev/null +++ b/fpga/usrp3/lib/wishbone/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 |