//---------------------------------------------------------------------------- // user_logic.v - module //---------------------------------------------------------------------------- // // *************************************************************************** // ** Copyright (c) 1995-2012 Xilinx, Inc. All rights reserved. ** // ** ** // ** Xilinx, Inc. ** // ** XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS" ** // ** AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND ** // ** SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE, ** // ** OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE, ** // ** APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION ** // ** THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT, ** // ** AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE ** // ** FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY ** // ** WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE ** // ** IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR ** // ** REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF ** // ** INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ** // ** FOR A PARTICULAR PURPOSE. ** // ** ** // *************************************************************************** // //---------------------------------------------------------------------------- // Filename: user_logic.v // Version: 1.00.b // Description: User logic module. // Date: Sat Feb 23 20:58:52 2013 (by Create and Import Peripheral Wizard) // Verilog Standard: Verilog-2001 //---------------------------------------------------------------------------- // Naming Conventions: // active low signals: "*_n" // clock signals: "clk", "clk_div#", "clk_#x" // reset signals: "rst", "rst_n" // generics: "C_*" // user defined types: "*_TYPE" // state machine next state: "*_ns" // state machine current state: "*_cs" // combinatorial signals: "*_com" // pipelined or register delay signals: "*_d#" // counter signals: "*cnt*" // clock enable signals: "*_ce" // internal version of output port: "*_i" // device pins: "*_pin" // ports: "- Names begin with Uppercase" // processes: "*_PROCESS" // component instantiations: "I_<#|FUNC>" //---------------------------------------------------------------------------- `uselib lib=unisims_ver `uselib lib=proc_common_v3_00_a module user_logic ( // -- ADD USER PORTS BELOW THIS LINE --------------- iic_scl, iic_sda, // -- ADD USER PORTS ABOVE THIS LINE --------------- // -- DO NOT EDIT BELOW THIS LINE ------------------ // -- Bus protocol ports, do not add to or delete Bus2IP_Clk, // Bus to IP clock Bus2IP_Resetn, // Bus to IP reset Bus2IP_Data, // Bus to IP data bus Bus2IP_BE, // Bus to IP byte enables Bus2IP_RdCE, // Bus to IP read chip enable Bus2IP_WrCE, // Bus to IP write chip enable IP2Bus_Data, // IP to Bus data bus IP2Bus_RdAck, // IP to Bus read transfer acknowledgement IP2Bus_WrAck, // IP to Bus write transfer acknowledgement IP2Bus_Error // IP to Bus error response // -- DO NOT EDIT ABOVE THIS LINE ------------------ ); // user_logic // -- ADD USER PARAMETERS BELOW THIS LINE ------------ // --USER parameters added here // -- ADD USER PARAMETERS ABOVE THIS LINE ------------ // -- DO NOT EDIT BELOW THIS LINE -------------------- // -- Bus protocol parameters, do not add to or delete parameter C_NUM_REG = 8; parameter C_SLV_DWIDTH = 32; // -- DO NOT EDIT ABOVE THIS LINE -------------------- // -- ADD USER PORTS BELOW THIS LINE ----------------- inout iic_scl; inout iic_sda; // -- ADD USER PORTS ABOVE THIS LINE ----------------- // -- DO NOT EDIT BELOW THIS LINE -------------------- // -- Bus protocol ports, do not add to or delete input Bus2IP_Clk; input Bus2IP_Resetn; input [C_SLV_DWIDTH-1 : 0] Bus2IP_Data; input [C_SLV_DWIDTH/8-1 : 0] Bus2IP_BE; input [C_NUM_REG-1 : 0] Bus2IP_RdCE; input [C_NUM_REG-1 : 0] Bus2IP_WrCE; output [C_SLV_DWIDTH-1 : 0] IP2Bus_Data; output IP2Bus_RdAck; output IP2Bus_WrAck; output IP2Bus_Error; // -- DO NOT EDIT ABOVE THIS LINE -------------------- //---------------------------------------------------------------------------- // Implementation //---------------------------------------------------------------------------- // --USER nets declarations added here, as needed for user logic // Nets for user logic slave model s/w accessible register example reg [C_SLV_DWIDTH-1 : 0] slv_reg0; reg [C_SLV_DWIDTH-1 : 0] slv_reg1; reg [C_SLV_DWIDTH-1 : 0] slv_reg2; reg [C_SLV_DWIDTH-1 : 0] slv_reg3; reg [C_SLV_DWIDTH-1 : 0] slv_reg4; reg [C_SLV_DWIDTH-1 : 0] slv_reg5; reg [C_SLV_DWIDTH-1 : 0] slv_reg6; reg [C_SLV_DWIDTH-1 : 0] slv_reg7; wire [7 : 0] slv_reg_write_sel; wire [7 : 0] slv_reg_read_sel; reg [C_SLV_DWIDTH-1 : 0] slv_ip2bus_data; wire slv_read_ack; wire slv_write_ack; integer byte_index, bit_index; // USER logic implementation added here // ------------------------------------------------------ // Example code to read/write user logic slave model s/w accessible registers // // Note: // The example code presented here is to show you one way of reading/writing // software accessible registers implemented in the user logic slave model. // Each bit of the Bus2IP_WrCE/Bus2IP_RdCE signals is configured to correspond // to one software accessible register by the top level template. For example, // if you have four 32 bit software accessible registers in the user logic, // you are basically operating on the following memory mapped registers: // // Bus2IP_WrCE/Bus2IP_RdCE Memory Mapped Register // "1000" C_BASEADDR + 0x0 // "0100" C_BASEADDR + 0x4 // "0010" C_BASEADDR + 0x8 // "0001" C_BASEADDR + 0xC // // ------------------------------------------------------ assign slv_reg_write_sel = Bus2IP_WrCE[7:0], slv_reg_read_sel = Bus2IP_RdCE[7:0], slv_write_ack = Bus2IP_WrCE[0] || Bus2IP_WrCE[1] || Bus2IP_WrCE[2] || Bus2IP_WrCE[3] || Bus2IP_WrCE[4] || Bus2IP_WrCE[5] || Bus2IP_WrCE[6] || Bus2IP_WrCE[7], slv_read_ack = Bus2IP_RdCE[0] || Bus2IP_RdCE[1] || Bus2IP_RdCE[2] || Bus2IP_RdCE[3] || Bus2IP_RdCE[4] || Bus2IP_RdCE[5] || Bus2IP_RdCE[6] || Bus2IP_RdCE[7]; // implement slave model register(s) always @( posedge Bus2IP_Clk ) begin if ( Bus2IP_Resetn == 1'b0 ) begin slv_reg0 <= 0; slv_reg1 <= 0; slv_reg2 <= 0; slv_reg3 <= 0; slv_reg4 <= 0; slv_reg5 <= 0; slv_reg6 <= 0; slv_reg7 <= 0; end else case ( slv_reg_write_sel ) 8'b10000000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg0[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b01000000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg1[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00100000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg2[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00010000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg3[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00001000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg4[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00000100 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg5[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00000010 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg6[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; 8'b00000001 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) slv_reg7[(byte_index*8) +: 8] <= Bus2IP_Data[(byte_index*8) +: 8]; default : begin slv_reg0 <= slv_reg0; slv_reg1 <= slv_reg1; slv_reg2 <= slv_reg2; slv_reg3 <= slv_reg3; slv_reg4 <= slv_reg4; slv_reg5 <= slv_reg5; slv_reg6 <= slv_reg6; slv_reg7 <= slv_reg7; end endcase end // SLAVE_REG_WRITE_PROC // implement slave model register read mux always @* begin case ( slv_reg_read_sel ) 8'b10000000 : slv_ip2bus_data <= slv_reg0_rd; 8'b01000000 : slv_ip2bus_data <= slv_reg1; 8'b00100000 : slv_ip2bus_data <= slv_reg2; 8'b00010000 : slv_ip2bus_data <= slv_reg3_rd; 8'b00001000 : slv_ip2bus_data <= slv_reg4; 8'b00000100 : slv_ip2bus_data <= slv_reg5; 8'b00000010 : slv_ip2bus_data <= slv_reg6; 8'b00000001 : slv_ip2bus_data <= slv_reg7; default : slv_ip2bus_data <= 0; endcase end // SLAVE_REG_READ_PROC // ------------------------------------------------------------ // Example code to drive IP to Bus signals // ------------------------------------------------------------ assign IP2Bus_Data = (slv_read_ack == 1'b1) ? slv_ip2bus_data : 0 ; assign IP2Bus_WrAck = slv_write_ack; assign IP2Bus_RdAck = slv_read_ack; assign IP2Bus_Error = 0; /* Address map: HDL is coded [MSB:LSB] = [31:0] regX[31] maps to 0x80000000 in C driver regX[0] maps to 0x00000001 in C driver 0: Config/Status[31:0]: [ 7: 0] clk divider (see comments below for interpretation) RW 0x000000FF [8] core enable (1=enabled, 0=disabled) RW 0x00000100 [15: 9] reserved 0x0000FE00 [16] RxACK: received ACK from slave (1=received ACK) RO 0x00010000 [17] Busy: IIC bus busy (1 between Start and Stop events) RO 0x00020000 [18] AL: Arbitration lost (1 when Stop detected but not requested) RO 0x00040000 [19] TIP: Transfer in progress (1 during transfer) RO 0x00080000 [31:20] Reserved 1: Command[31:0]: RW, self-clearing, uses local reg, not normal slv_reg1 [0] Start: generate IIC start 0x01 [1] Stop: generate IIC stop 0x02 [2] Read: execute IIC read 0x04 [3] Write: execute IIC write 0x08 [4] ACK: send ACK for current transaction 0x10 [31:5]: Reserved 2: Transmit[31:0]: {24'b0, txByte[7:0]} RW [ 7: 0]: Tx Byte ([31]=RNW during control word writes) [31: 8]: Reserved 3: Receive[31:0]: {24'b0, rxByte[7:0]} RO [ 7: 0]: Rx Byte [31: 8]: Reserved */ reg [4:0] cmd_reg; wire core_en; wire [15:0] clk_div; wire cmd_start, cmd_stop, cmd_read, cmd_write, cmd_ack; wire [7:0] iic_tx_byte; wire [7:0] iic_rx_byte; wire iic_rx_ack; wire iic_bus_busy; wire iic_al; wire iic_done; wire iic_tip; wire slv_reg1_WE; assign slv_reg1_WE = Bus2IP_WrCE[6]; //WrCE/RdCE[7:0] map to slv_reg[0:7] //Custom command register logic, implements self-clearing bits always @( posedge Bus2IP_Clk ) begin if ( Bus2IP_Resetn == 1'b0 ) cmd_reg <= 5'b0; else if(slv_reg1_WE == 1'b1) cmd_reg[4:0] <= Bus2IP_Data[4:0]; else if(iic_done | iic_al) begin //Clear start, stop, read, write bits on transfer completion or arbitration loss // cmd_reg[4:1] <= 4'b0; // cmd_reg[0] <= cmd_reg[0]; cmd_reg[3:0] <= 4'b0; cmd_reg[4] <= cmd_reg[4]; end else cmd_reg[4:0] <= cmd_reg[4:0]; end assign cmd_start = cmd_reg[0]; //0x01 from driver assign cmd_stop = cmd_reg[1]; //0x02 assign cmd_read = cmd_reg[2]; //0x04 assign cmd_write = cmd_reg[3]; //0x08 assign cmd_ack = cmd_reg[4]; //0x10 assign iic_tip = (cmd_read | cmd_write); //register bits self-clear on transfer completion //Construct 32-bit vectors for read access to mixed RW/RO registers wire [31:0] slv_reg0_rd; wire [31:0] slv_reg3_rd; assign slv_reg0_rd = {12'b0, iic_tip, iic_al, iic_bus_busy, iic_rx_ack, 7'b0, slv_reg0[8], slv_reg0[7:0]}; assign slv_reg3_rd = {24'b0, iic_rx_byte[7:0]}; //IIC master divides down master clock to generate SCL // SCL rate is (sys_clk / (5*clk_div[0:15])) // For 200MHz sys_clk and 100kHz SCL, clk_div = 400 = 0x190 // Interpret user-provided clock divider as bits[6:13] of clk_div assign clk_div[15:0] = {6'b0, slv_reg0[7:0], 2'b0}; assign core_en = slv_reg0[8]; assign iic_tx_byte = slv_reg2[7:0]; wire sda_pad_i, sda_pad_o, sda_pad_oe; wire scl_pad_i, scl_pad_o, scl_pad_oe; IOBUF IOBUF_sda ( .IO(iic_sda), //Connected to actual FPGA pin .I(sda_pad_o), //Logic-> Pad, input to OBUFT .O(sda_pad_i), //Pad-> Logic, output of IBUF .T(sda_pad_oe) ); IOBUF IOBUF_scl ( .IO(iic_scl), //Connected to actual FPGA pin .I(scl_pad_o), //Logic-> Pad, input to OBUFT .O(scl_pad_i), //Pad-> Logic, output of IBUF .T(scl_pad_oe) ); i2c_master_byte_ctrl byte_controller ( .clk ( Bus2IP_Clk ), //master clock .rst ( ~Bus2IP_Resetn ), //synchronous reset, active high .nReset ( 1'b1 ), //asynchronous reset, acvtive low .ena ( core_en ), //core enable, active high .clk_cnt ( clk_div ), //master-to-iic clock divider .start ( cmd_start ), //send iic start .stop ( cmd_stop ), //send iic stop .read ( cmd_read ), //perform iic read .write ( cmd_write ), //perform iic write .ack_in ( cmd_ack ), //send iic ack .din ( iic_tx_byte ), //byte to send .cmd_ack ( iic_done ), //xfer is done .ack_out ( iic_rx_ack ), //ack from slave .dout ( iic_rx_byte ), //byte read from slave .i2c_busy ( iic_bus_busy ), .i2c_al ( iic_al ), //arbitration lost output .scl_i ( scl_pad_i ), //iic scl input (pad -> logic) .scl_o ( scl_pad_o ), //iic scl output (logic -> pad) .scl_oen ( scl_pad_oe ), //iic scl output enable (0=scl is logic-driven output) .sda_i ( sda_pad_i ), //iic sda input (pad -> logic) .sda_o ( sda_pad_o ), //iic sda output (logic -> pad) .sda_oen ( sda_pad_oe ) //iic sda output enable (0=sda is logic-driven output) ); endmodule