//---------------------------------------------------------------------------- // user_logic.vhd - module //---------------------------------------------------------------------------- // // *************************************************************************** // ** Copyright (c) 1995-2011 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.vhd // Version: 1.00.a // Description: User logic module. // Date: Sun May 27 20:04:18 2012 (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>" //---------------------------------------------------------------------------- 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_Reset, // 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_SLV_DWIDTH = 32; parameter C_NUM_REG = 8; // -- 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_Reset; input [0 : C_SLV_DWIDTH-1] Bus2IP_Data; input [0 : C_SLV_DWIDTH/8-1] Bus2IP_BE; input [0 : C_NUM_REG-1] Bus2IP_RdCE; input [0 : C_NUM_REG-1] Bus2IP_WrCE; output [0 : C_SLV_DWIDTH-1] 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 [0 : C_SLV_DWIDTH-1] slv_reg0; reg [0 : C_SLV_DWIDTH-1] slv_reg1; reg [0 : C_SLV_DWIDTH-1] slv_reg2; reg [0 : C_SLV_DWIDTH-1] slv_reg3; reg [0 : C_SLV_DWIDTH-1] slv_reg4; reg [0 : C_SLV_DWIDTH-1] slv_reg5; reg [0 : C_SLV_DWIDTH-1] slv_reg6; reg [0 : C_SLV_DWIDTH-1] slv_reg7; wire [0 : 7] slv_reg_write_sel; wire [0 : 7] slv_reg_read_sel; reg [0 : C_SLV_DWIDTH-1] 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[0:7], slv_reg_read_sel = Bus2IP_RdCE[0:7], 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: SLAVE_REG_WRITE_PROC if ( Bus2IP_Reset == 1 ) 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 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg0[bit_index] <= Bus2IP_Data[bit_index]; 8'b01000000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg1[bit_index] <= Bus2IP_Data[bit_index]; 8'b00100000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg2[bit_index] <= Bus2IP_Data[bit_index]; 8'b00010000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg3[bit_index] <= Bus2IP_Data[bit_index]; 8'b00001000 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg4[bit_index] <= Bus2IP_Data[bit_index]; 8'b00000100 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg5[bit_index] <= Bus2IP_Data[bit_index]; 8'b00000010 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg6[bit_index] <= Bus2IP_Data[bit_index]; 8'b00000001 : for ( byte_index = 0; byte_index <= (C_SLV_DWIDTH/8)-1; byte_index = byte_index+1 ) if ( Bus2IP_BE[byte_index] == 1 ) for ( bit_index = byte_index*8; bit_index <= byte_index*8+7; bit_index = bit_index+1 ) slv_reg7[bit_index] <= Bus2IP_Data[bit_index]; default : ; endcase end // SLAVE_REG_WRITE_PROC // implement slave model register read mux always @* begin: SLAVE_REG_READ_PROC 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_ip2bus_data; assign IP2Bus_WrAck = slv_write_ack; assign IP2Bus_RdAck = slv_read_ack; assign IP2Bus_Error = 0; /* Address map: HDL is coded [MSB:LSB] = [0:31] regX[0] maps to 0x80000000 in C driver regX[31] maps to 0x00000001 in C driver 0: Config/Status[0:31]: {23'b0, core_en, clk_div[0:7]} RW [24:31] clk divider (see comments below for interpretation) RW 0x000000FF [ 23] core enable (1=enabled, 0=disabled) RW 0x00000100 [16:22] reserved 0x0000FE00 [15] RxACK: received ACK from slave (1=received ACK) RO 0x00010000 [14] Busy: IIC bus busy (1 between Start and Stop events) RO 0x00020000 [13] AL: Arbitration lost (1 when Stop detected but not requested) RO 0x00040000 [12] TIP: Transfer in progress (1 during transfer) RO 0x00080000 [0:11] Reserved 1: Command[0:31]: RW, self-clearing, uses local reg, not normal slv_reg1 [31] Start: generate IIC start 0x01 [30] Stop: generate IIC stop 0x02 [29] Read: execute IIC read 0x04 [28] Write: execute IIC write 0x08 [27] ACK: send ACK for current transaction 0x10 [0:26]: Reserved 2: Transmit[0:31]: {24'b0, txByte[0:8]} RW [24:31]: Tx Byte ([31]=RNW during control word writes) [0 :23]: Reserved 3: Receive[0:31]: {24'b0, rxByte[0:8]} RO [24:31]: Rx Byte [0 :23]: Reserved */ reg [0:4] cmd_reg; wire core_en; wire [0:15] clk_div; wire cmd_start, cmd_stop, cmd_read, cmd_write, cmd_ack; wire [0:7] iic_tx_byte; wire [0:7] iic_rx_byte; wire iic_rx_ack; wire iic_bus_busy; wire iic_al; wire iic_done; wire iic_tip; //Custom command register logic, implements self-clearing bits always @( posedge Bus2IP_Clk ) begin if ( Bus2IP_Reset == 1'b1 ) cmd_reg <= 5'b0; else if(Bus2IP_WrCE[1] == 1'b1) cmd_reg[0:4] <= Bus2IP_Data[27:31]; else if(iic_done | iic_al) begin //Clear start, stop, read, write bits on transfer completion or arbitration loss // cmd_reg[0:3] <= 4'b0; // cmd_reg[4] <= cmd_reg[4]; cmd_reg[1:4] <= 4'b0; cmd_reg[0] <= cmd_reg[0]; end else cmd_reg[0:4] <= cmd_reg[0:4]; end assign cmd_start = cmd_reg[4]; //0x01 from driver assign cmd_stop = cmd_reg[3]; //0x02 assign cmd_read = cmd_reg[2]; //0x04 assign cmd_write = cmd_reg[1]; //0x08 assign cmd_ack = cmd_reg[0]; //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 [0:31] slv_reg0_rd; wire [0:31] slv_reg3_rd; assign slv_reg0_rd = {12'b0, iic_tip, iic_al, iic_bus_busy, iic_rx_ack, 7'b0, slv_reg0[23:31]}; assign slv_reg3_rd = {24'b0, iic_rx_byte[0:7]}; //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[0:15] = {6'b0, slv_reg0[24:31], 2'b0}; assign core_en = slv_reg0[23]; assign iic_tx_byte = slv_reg2[24:31]; 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_Reset ), //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