From 1b595ed5687c2069a8850b0c130f3210388c1f5c Mon Sep 17 00:00:00 2001 From: twl Date: Sun, 22 Dec 2013 15:36:11 +0100 Subject: [PATCH] initial commit --- LICENSE | 165 ++++++ README | 14 + hdl/.gitignore | 4 + hdl/rtl/dsi_core/Manifest.py | 9 + hdl/rtl/dsi_core/dphy_lane.v | 275 ++++++++++ hdl/rtl/dsi_core/dphy_serdes.v | 248 +++++++++ hdl/rtl/dsi_core/dsi_core.v | 455 ++++++++++++++++ hdl/rtl/dsi_core/dsi_defs.vh | 55 ++ hdl/rtl/dsi_core/dsi_fifo.v | 128 +++++ hdl/rtl/dsi_core/dsi_packer.v | 238 ++++++++ hdl/rtl/dsi_core/dsi_packet_assembler.v | 264 +++++++++ hdl/rtl/dsi_core/dsi_test_image_gen.v | 185 +++++++ hdl/rtl/dsi_core/dsi_timing_gen.v | 237 ++++++++ hdl/rtl/dsi_core/dsi_utils.v | 109 ++++ hdl/syn/spec/Manifest.py | 14 + hdl/syn/spec/boot.ram | 1 + hdl/syn/spec/dsi_test.xise | 693 ++++++++++++++++++++++++ hdl/top/spec/Manifest.py | 8 + hdl/top/spec/dsi_pll_spartan6.v | 142 +++++ hdl/top/spec/spec_reset_gen.vhd | 55 ++ hdl/top/spec/spec_top.ucf | 90 +++ hdl/top/spec/spec_top.vhd | 259 +++++++++ 22 files changed, 3648 insertions(+) create mode 100644 LICENSE create mode 100644 README create mode 100644 hdl/.gitignore create mode 100644 hdl/rtl/dsi_core/Manifest.py create mode 100644 hdl/rtl/dsi_core/dphy_lane.v create mode 100644 hdl/rtl/dsi_core/dphy_serdes.v create mode 100644 hdl/rtl/dsi_core/dsi_core.v create mode 100644 hdl/rtl/dsi_core/dsi_defs.vh create mode 100644 hdl/rtl/dsi_core/dsi_fifo.v create mode 100644 hdl/rtl/dsi_core/dsi_packer.v create mode 100644 hdl/rtl/dsi_core/dsi_packet_assembler.v create mode 100644 hdl/rtl/dsi_core/dsi_test_image_gen.v create mode 100644 hdl/rtl/dsi_core/dsi_timing_gen.v create mode 100644 hdl/rtl/dsi_core/dsi_utils.v create mode 100644 hdl/syn/spec/Manifest.py create mode 120000 hdl/syn/spec/boot.ram create mode 100644 hdl/syn/spec/dsi_test.xise create mode 100644 hdl/top/spec/Manifest.py create mode 100644 hdl/top/spec/dsi_pll_spartan6.v create mode 100644 hdl/top/spec/spec_reset_gen.vhd create mode 100644 hdl/top/spec/spec_top.ucf create mode 100644 hdl/top/spec/spec_top.vhd diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/README b/README new file mode 100644 index 0000000..a94b981 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +DSI Core Readme +------------------------ + +0. Disclaimer + +This project implements a MIPI DSI (MIPI Display Serial Interface) Verilog core. +Since the DSI specification is non-public and requires an NDA, the core is based on +using bits and pieces available throughout the Web: presentations, display controller/SOC +datasheets, various application notes and Android kernel drivers. The author is not +associated in any way with the MIPI Alliance. The core is provided as-is, it has never been +verified for compliance with the DSI standard and it probably lacks many of its features. +To sum up: you use it at your own risk, there's no warranty. + + \ No newline at end of file diff --git a/hdl/.gitignore b/hdl/.gitignore new file mode 100644 index 0000000..a7e9f5c --- /dev/null +++ b/hdl/.gitignore @@ -0,0 +1,4 @@ +*.zip +work +transcript +*.vlf diff --git a/hdl/rtl/dsi_core/Manifest.py b/hdl/rtl/dsi_core/Manifest.py new file mode 100644 index 0000000..fa11c4b --- /dev/null +++ b/hdl/rtl/dsi_core/Manifest.py @@ -0,0 +1,9 @@ +files = ["dphy_lane.v", +"dphy_serdes.v", +"dsi_core.v", +"dsi_fifo.v", +"dsi_packer.v", +"dsi_packet_assembler.v", +"dsi_test_image_gen.v", +"dsi_timing_gen.v", +"dsi_utils.v"] diff --git a/hdl/rtl/dsi_core/dphy_lane.v b/hdl/rtl/dsi_core/dphy_lane.v new file mode 100644 index 0000000..202a04e --- /dev/null +++ b/hdl/rtl/dsi_core/dphy_lane.v @@ -0,0 +1,275 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`timescale 1ns/1ps + +/* + * dphy_lane.v + * + * Implements a state and serdes control for a single lane of + * the DSI link. Responsible for LP/HS-mode switching, serialization, trailing + * sequences, LP data transmissions and many other things... + */ + +module dphy_lane + ( + // system clock + input clk_i, + input rst_n_i, + + // slow clock tick for timing LP transmissions + input tick_i, + + // High-speed mode TX interface + + // requests transition to HS mode + input hs_request_i, + // indicates a valid HS byte to send + input hs_valid_i, + // HS byte to send + input [7:0] hs_data_i, + // HS mode data request + output reg hs_ready_o, + + // Low-power (Escape) mode TX interface + // Requests LP mode + input lp_request_i, + // Low-power data word to be sent + input [7:0] lp_data_i, + // Strobe for lp_data_i + input lp_valid_i, + output reg lp_ready_o, + + output reg idle_o, + + // HS SerDes output + output reg [7:0] serdes_data_o, + output reg serdes_oe_o, + + // LP buffer outputs + output lp_txp_o, + output lp_txn_o, + output reg lp_oe_o + ); + + // when true, the lane polarity (both HS and LP) is inverted. Useful for PCB design. + parameter integer g_invert = 0; + +`define LP_ACTIVE 0 +`define LP_POWERUP 1 +`define LP_REQUEST_LPDT0 2 +`define LP_REQUEST_LPDT1 3 +`define LP_REQUEST_LPDT2 4 +`define LP_REQUEST_LPDT3 5 +`define LP_WAIT_TX 6 +`define LP_START_TX 7 +`define LP_NEXT_BIT 8 +`define LP_MARK_BIT 9 +`define LP_EXIT0 10 +`define LP_EXIT1 11 +`define LP_SPACE 12 +`define LP_REQUEST_HS0 13 +`define LP_REQUEST_HS1 14 +`define LP_HS_ACTIVE 15 +`define LP_HS_EXIT0 16 +`define LP_HS_EXIT1 17 +`define LP_HS_EXIT2 23 + + reg lp_txp_int, lp_txn_int; + + reg [4:0] lp_state; + reg [7:0] lp_sreg; + reg [3:0] tx_count; + + reg lp_hs_entered; + reg serdes_data_lastbit; + +`define LP_TX(txp, txn, next_lp_state) \ + begin lp_oe_o <= 1;\ + lp_txp_int <= txp;\ + lp_txn_int <= txn;\ + if(tick_i)\ + lp_state <= next_lp_state; end + + always@(posedge clk_i or negedge rst_n_i) + begin + if (!rst_n_i) begin + lp_state <= `LP_ACTIVE; + lp_txn_int <= 1; + lp_txp_int <= 1; + lp_oe_o <= 0; + lp_hs_entered <= 0; + lp_ready_o <= 0; + idle_o <= 1; + + end else begin + case (lp_state) + `LP_ACTIVE : begin + lp_hs_entered <= 0; + lp_oe_o <= 1; + lp_txn_int <= 1; + lp_txp_int <= 1; + lp_ready_o <= 0; + idle_o <= 1; + + + if(tick_i) begin + idle_o <= 0; + + if(lp_request_i) + lp_state <= `LP_REQUEST_LPDT0; + else if(hs_request_i) + lp_state <= `LP_REQUEST_HS0; + else + idle_o <= 1; + end + end // case: `LP_ACTIVE + + `LP_REQUEST_HS0: + `LP_TX(0,1,`LP_REQUEST_HS1) + + `LP_REQUEST_HS1: + `LP_TX(0,0,`LP_HS_ACTIVE) + + `LP_HS_ACTIVE: begin + lp_oe_o <= 0; + lp_hs_entered <= 1; + + if(!hs_request_i) + lp_state <= `LP_HS_EXIT0; + end + + `LP_HS_EXIT0: + if(tick_i) begin + lp_txn_int <= 1; + lp_txp_int <= 1; + lp_state <= `LP_ACTIVE; + end + + `LP_HS_EXIT1: + if(tick_i) begin + lp_hs_entered <= 0; + lp_state <= `LP_HS_EXIT2; + end + + `LP_HS_EXIT2: begin + lp_oe_o <= 1; + lp_txn_int <= 1; + lp_txp_int <= 1; + lp_hs_entered <= 0; + lp_state <= `LP_ACTIVE; + end + + + `LP_REQUEST_LPDT0: + `LP_TX(1,0,`LP_REQUEST_LPDT1) + + `LP_REQUEST_LPDT1: + `LP_TX(0,0,`LP_REQUEST_LPDT2) + + `LP_REQUEST_LPDT2: + `LP_TX(0,1,`LP_REQUEST_LPDT3) + + `LP_REQUEST_LPDT3: + `LP_TX(0,0,`LP_WAIT_TX) + + `LP_WAIT_TX: + lp_state <= `LP_START_TX; + + `LP_START_TX: begin + + if(!lp_request_i) begin + lp_state <= `LP_EXIT0; + lp_ready_o <= 0; + + end else if (lp_valid_i) begin + lp_sreg <= lp_data_i; + lp_state <= `LP_NEXT_BIT; + tx_count <= 8; + lp_ready_o <= 0; + + end else + lp_ready_o <= 1; + + end + + `LP_NEXT_BIT: begin + if(!tx_count) + lp_state <= `LP_WAIT_TX; + else if(tick_i) begin + tx_count <= tx_count - 1; + lp_txp_int<=lp_sreg[7] ; + lp_txn_int<=~lp_sreg[7]; + lp_sreg <= lp_sreg << 1; + lp_state <= `LP_MARK_BIT; + end + end // case: `LP_NEXT_BIT + + `LP_MARK_BIT: + if(tick_i)begin + lp_txp_int <= 0; + lp_txn_int <= 0; + lp_state <= `LP_SPACE; + end + + `LP_SPACE: + if(tick_i)begin + lp_state <= `LP_NEXT_BIT; + end + + `LP_EXIT0: + `LP_TX(1, 0, `LP_EXIT1) + + `LP_EXIT1: + `LP_TX(1, 1, `LP_ACTIVE) + endcase + end + end + + + always@(posedge clk_i) + if(lp_state == `LP_HS_ACTIVE && hs_request_i && hs_valid_i) + serdes_data_lastbit <= (g_invert ? ~hs_data_i[7] : hs_data_i[7]); + + always@(hs_data_i, hs_valid_i, lp_hs_entered, lp_state, serdes_data_lastbit) + begin + // trailing sequence when exiting HS (inverse of last transmitted bit) + if(lp_state == `LP_HS_EXIT0 || lp_state == `LP_HS_EXIT1 || lp_state == `LP_HS_EXIT2) + serdes_data_o <= {8{~serdes_data_lastbit}}; + else if(hs_valid_i) + serdes_data_o <= (g_invert ? ~hs_data_i : hs_data_i); + // leading sequence (all 0's) + else + serdes_data_o <= (g_invert ? 8'hff:8'h00); + serdes_oe_o <= lp_hs_entered; + end + + assign lp_txp_o = (g_invert ? lp_txn_int : lp_txp_int); + assign lp_txn_o = (g_invert ? lp_txp_int : lp_txn_int); + + always@(posedge clk_i) + if(!rst_n_i) + hs_ready_o <= 0; + else if(tick_i && lp_hs_entered) + hs_ready_o <= 1; + else if(!hs_request_i) + hs_ready_o <= 0; + +endmodule + + diff --git a/hdl/rtl/dsi_core/dphy_serdes.v b/hdl/rtl/dsi_core/dphy_serdes.v new file mode 100644 index 0000000..cc6b1de --- /dev/null +++ b/hdl/rtl/dsi_core/dphy_serdes.v @@ -0,0 +1,248 @@ +// file: dphy_serdes.v +// (c) Copyright 2009 - 2011 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +//---------------------------------------------------------------------------- + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "dphy_serdes,selectio_wiz_v3_2,{component_name=dphy_serdes,bus_dir=OUTPUTS,bus_sig_type=DIFF,bus_io_std=LVDS_25,use_serialization=true,use_phase_detector=false,serialization_factor=8,enable_bitslip=false,enable_train=false,system_data_width=3,bus_in_delay=NONE,bus_out_delay=NONE,clk_sig_type=SINGLE,clk_io_std=LVCMOS18,clk_buf=BUFPLL,active_edge=RISING,clk_delay=NONE,v6_bus_in_delay=NONE,v6_bus_out_delay=NONE,v6_clk_buf=BUFIO,v6_active_edge=NOT_APP,v6_ddr_alignment=SAME_EDGE_PIPELINED,v6_oddr_alignment=SAME_EDGE,ddr_alignment=C0,v6_interface_type=NETWORKING,interface_type=NETWORKING,v6_bus_in_tap=0,v6_bus_out_tap=0,v6_clk_io_std=LVCMOS18,v6_clk_sig_type=DIFF}" *) + +module dphy_serdes + // width of the data for the system + #(parameter sys_w = 3, + // width of the data for the device + parameter dev_w = 24) + ( + // From the device out to the system + input [dev_w-1:0] DATA_OUT_FROM_DEVICE, + output [sys_w-1:0] DATA_OUT_TO_PINS_P, + output [sys_w-1:0] DATA_OUT_TO_PINS_N, + input CLK_IN, // Fast clock input from PLL/MMCM + input CLK_DIV_IN, // Slow clock input from PLL/MMCM + input LOCKED_IN, + output LOCKED_OUT, + input CLK_RESET, + input IO_RESET, + input [sys_w-1:0] OE); + + localparam num_serial_bits = dev_w/sys_w; + // Signal declarations + ////------------------------------ + wire clock_enable = 1'b1; + // Before the buffer + wire [sys_w-1:0] data_out_to_pins_int; + // Between the delay and serdes + wire [sys_w-1:0] data_out_to_pins_predelay; + // Array to use intermediately from the serdes to the internal + // devices. bus "0" is the leftmost bus + wire [sys_w-1:0] oserdes_d[0:7]; // fills in starting with 7 + // Create the clock logic + BUFPLL + #(.DIVIDE (8)) + bufpll_inst + (.IOCLK (clk_in_int_buf), + .LOCK (LOCKED_OUT), + .SERDESSTROBE (serdesstrobe), + .GCLK (CLK_DIV_IN), // GCLK must be driven by BUFG + .LOCKED (LOCKED_IN), + .PLLIN (CLK_IN)); + + // We have multiple bits- step over every bit, instantiating the required elements + genvar pin_count; + genvar slice_count; + + wire [sys_w-1:0] oe_int_n; + wire [sys_w-1:0] tq_out; + + + generate for (pin_count = 0; pin_count < sys_w; pin_count = pin_count + 1) begin: pins + // Instantiate the buffers + ////------------------------------ + // Instantiate a buffer for every bit of the data bus + + OBUFTDS + #(.IOSTANDARD ("DIFF_SSTL2_II")) + obufds_inst + (.O (DATA_OUT_TO_PINS_P [pin_count]), + .OB (DATA_OUT_TO_PINS_N [pin_count]), + .T (tq_out[pin_count]), + .I (data_out_to_pins_int[pin_count])); + +// always@(posedge CLK_DIV_IN) + assign oe_int_n[pin_count] = ~OE[pin_count]; + + // Instantiate the delay primitive + ////------------------------------- + IODELAY2 + #(.DATA_RATE ("SDR"), + .ODELAY_VALUE (pin_count != sys_w - 1 ? 100 : 0), + .COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), + .DELAY_SRC ("ODATAIN"), + .SERDES_MODE ("NONE"), + .SIM_TAPDELAY_VALUE (75)) + iodelay2_bus + ( + // required datapath + .T (1'b0), + .DOUT (data_out_to_pins_int [pin_count]), + .ODATAIN (data_out_to_pins_predelay[pin_count]), + // inactive data connections + .IDATAIN (1'b0), + .TOUT (), + .DATAOUT (), + .DATAOUT2 (), + // connect up the clocks + .IOCLK0 (1'b0), // No calibration needed + .IOCLK1 (1'b0), // No calibration needed + // Tie of the variable delay programming + .CLK (CLK_DIV_IN), + .CAL (1'b0), + .INC (1'b0), + .CE (1'b0), + .BUSY (), + .RST (IO_RESET)); + // assign data_out_to_pins_int[pin_count] = data_out_to_pins_predelay[pin_count]; + + // Instantiate the serdes primitive + ////------------------------------ + // local wire only for use in this generate loop + wire cascade_ms_d; + wire cascade_ms_t; + wire cascade_sm_d; + wire cascade_sm_t; + + // declare the oserdes + OSERDES2 + #(.DATA_RATE_OQ ("SDR"), + .DATA_RATE_OT ("SDR"), + .TRAIN_PATTERN (0), + .DATA_WIDTH (num_serial_bits), + .SERDES_MODE ("MASTER"), + .OUTPUT_MODE ("DIFFERENTIAL")) + oserdes2_master + (.D1 (oserdes_d[3][pin_count]), + .D2 (oserdes_d[2][pin_count]), + .D3 (oserdes_d[1][pin_count]), + .D4 (oserdes_d[0][pin_count]), + .T1 (oe_int_n[pin_count]), + .T2 (oe_int_n[pin_count]), + .T3 (oe_int_n[pin_count]), + .T4 (oe_int_n[pin_count]), + .SHIFTIN1 (1'b1), + .SHIFTIN2 (1'b1), + .SHIFTIN3 (cascade_sm_d), + .SHIFTIN4 (cascade_sm_t), + .SHIFTOUT1 (cascade_ms_d), + .SHIFTOUT2 (cascade_ms_t), + .SHIFTOUT3 (), + .SHIFTOUT4 (), + .TRAIN (1'b0), + .OCE (clock_enable), + .CLK0 (clk_in_int_buf), + .CLK1 (1'b0), + .CLKDIV (CLK_DIV_IN), + .OQ (data_out_to_pins_predelay[pin_count]), + .TQ (tq_out[pin_count]), + .IOCE (serdesstrobe), + .TCE (clock_enable), + .RST (IO_RESET)); + + + OSERDES2 + #(.DATA_RATE_OQ ("SDR"), + .DATA_RATE_OT ("SDR"), + .DATA_WIDTH (num_serial_bits), + .SERDES_MODE ("SLAVE"), + .TRAIN_PATTERN (0), + .OUTPUT_MODE ("DIFFERENTIAL")) + oserdes2_slave + (.D1 (oserdes_d[7][pin_count]), + .D2 (oserdes_d[6][pin_count]), + .D3 (oserdes_d[5][pin_count]), + .D4 (oserdes_d[4][pin_count]), + .T1 (oe_int_n[pin_count]), + .T2 (oe_int_n[pin_count]), + .T3 (oe_int_n[pin_count]), + .T4 (oe_int_n[pin_count]), + .SHIFTIN1 (cascade_ms_d), + .SHIFTIN2 (cascade_ms_t), + .SHIFTIN3 (1'b1), + .SHIFTIN4 (1'b1), + .SHIFTOUT1 (), + .SHIFTOUT2 (), + .SHIFTOUT3 (cascade_sm_d), + .SHIFTOUT4 (cascade_sm_t), + .TRAIN (1'b0), + .OCE (clock_enable), + .CLK0 (clk_in_int_buf), + .CLK1 (1'b0), + .CLKDIV (CLK_DIV_IN), + .OQ (), + .TQ (), + .IOCE (serdesstrobe), + .TCE (clock_enable), + .RST (IO_RESET)); + // Concatenate the serdes outputs together. Keep the timesliced + // bits together, and placing the earliest bits on the right + // ie, if data comes in 0, 1, 2, 3, 4, 5, 6, 7, ... + // the output will be 3210, 7654, ... + ////--------------------------------------------------------- + for (slice_count = 0; slice_count < num_serial_bits; slice_count = slice_count + 1) begin: out_slices + // This places the first data in time on the right + assign oserdes_d[8-slice_count-1] = + DATA_OUT_FROM_DEVICE[slice_count*sys_w+:sys_w]; + // To place the first data in time on the left, use the + // following code, instead + // assign oserdes_d[slice_count] = + // DATA_OUT_FROM_DEVICE[slice_count*sys_w+:sys_w]; + end + end + endgenerate +endmodule diff --git a/hdl/rtl/dsi_core/dsi_core.v b/hdl/rtl/dsi_core/dsi_core.v new file mode 100644 index 0000000..cfe2bf5 --- /dev/null +++ b/hdl/rtl/dsi_core/dsi_core.v @@ -0,0 +1,455 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`include "dsi_defs.vh" + +`timescale 1ns/1ps + +/* + * dsi_core.v + * + * Top level of the core. Currently works on Spartan-6 FPGAs only. + */ + + +module dsi_core + ( + // system clock (= pixel clock for the moment) + clk_sys_i, + // PHY serdes clock (= 8x pixel clock) + clk_phy_i, + + rst_n_i, + + pll_locked_i, + + frame_ready_o, + + // Pixel FIFO interface + fifo_full_o, + fifo_pixels_i, + fifo_frame_i, + fifo_wr_i, + + // DSI high speed output (OSERDES2) + dsi_hs_p_o, + dsi_hs_n_o, + + // DSI low power output + dsi_lp_p_o, + dsi_lp_n_o, + + // Lop power output enable + dsi_lp_oe_o, + + // DSI clock lane output + dsi_clk_p_o, + dsi_clk_n_o, + + // DSI clock lane LP signals + output enable + dsi_clk_lp_p_o, + dsi_clk_lp_n_o, + dsi_clk_lp_oe_o, + + // Displat reset pin + dsi_reset_n_o, + + // Host control registers + host_a_i, + host_d_i, + host_d_o, + host_wr_i + ); + + parameter g_pixels_per_clock = 1; + parameter g_lanes = 3; + parameter g_fifo_size = 1024; + parameter g_invert_lanes = 0; + parameter g_invert_clock = 0; + + localparam g_pixel_width = 24 * g_pixels_per_clock; + + input clk_sys_i, clk_phy_i, rst_n_i; + input pll_locked_i; + output frame_ready_o; + + + output fifo_full_o; + input [g_pixel_width - 1 : 0 ] fifo_pixels_i; + input fifo_frame_i, fifo_wr_i; + + output dsi_clk_p_o, dsi_clk_n_o; + output [g_lanes-1:0] dsi_hs_p_o, dsi_hs_n_o; + output [g_lanes-1:0] dsi_lp_p_o, dsi_lp_n_o; + output [g_lanes-1:0] dsi_lp_oe_o; + + output dsi_clk_lp_p_o, dsi_clk_lp_n_o; + output dsi_clk_lp_oe_o; + + output reg dsi_reset_n_o; + + input [5:0] host_a_i; + input [31:0] host_d_i; + output [31:0] host_d_o; + input host_wr_i; + + + /////////////////// + // PHY/Serdes layer + /////////////////// + + reg tick = 0; + + wire [g_lanes-1:0] phy_hs_ready_lane, lp_ready_lane, lp_readback_lane; + wire [g_lanes:0] serdes_oe_lane; + + + wire [g_lanes-1:0] lp_txp, lp_txn, lp_oe; + + wire lp_ready; + wire phy_hs_ready; + + assign lp_ready = lp_ready_lane[0]; + assign phy_hs_ready = phy_hs_ready_lane[0]; + + wire phy_hs_request; + wire [g_lanes * 8 -1 :0] phy_hs_data; + wire [g_lanes-1:0] phy_hs_valid; + wire [(g_lanes + 1) * 8 - 1: 0] serdes_data, serdes_data_interleaved; + reg r_dsi_clk_en = 0; + reg lp_request = 0; + reg lp_valid = 0; + reg [7:0] lp_data = 0; + + generate + genvar i; + for(i=0;i> ((g_lanes - 1 - i)*8)}), + .hs_ready_o (phy_hs_ready_lane[i]), + .hs_valid_i(phy_hs_valid[i]), + + .lp_request_i (lp_request), + .lp_data_i (lp_data), + .lp_valid_i (i ==0 ? lp_valid : 1'b0), + .lp_ready_o (lp_ready_lane[i]), + + .serdes_data_o(serdes_data[i*8+:8]), + + .lp_txp_o(lp_txp[i]), + .lp_txn_o(lp_txn[i]), + .lp_oe_o(lp_oe[i]) + ); + + assign dsi_lp_p_o[i] = lp_txp[i]; + assign dsi_lp_n_o[i] = lp_txn[i]; + assign dsi_lp_oe_o[i] = lp_oe[0]; + assign serdes_oe_lane[i] = ~lp_oe[0]; + + end // for (i=0;i + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`define PTYPE_VSYNC_START 6'h1 +`define PTYPE_VSYNC_END 6'h11 +`define PTYPE_HSYNC_START 6'h21 +`define PTYPE_HSYNC_END 6'h31 + +`define PTYPE_BLANKING 6'h19 +`define PTYPE_RGB24 6'h3e + +`define DSI_SYNC_SEQ 8'b10111000 + +`define REG_H_FRONT_PORCH 0 +`define REG_H_BACK_PORCH 1 +`define REG_H_ACTIVE 2 +`define REG_H_TOTAL 3 + +`define REG_V_FRONT_PORCH 4 +`define REG_V_BACK_PORCH 5 +`define REG_V_ACTIVE 6 +`define REG_V_TOTAL 7 + +`define REG_TIMING_CTL 8 +`define REG_TICK_DIV 9 +`define REG_DSI_CTL 10 + +`define REG_TEST_XSIZE 11 +`define REG_TEST_YSIZE 12 +`define REG_TEST_CTL 13 +`define REG_LP_TX 14 +`define REG_GPIO 15 + +`define REG_DBG_WADDR 16 +`define REG_DBG_RADDR 17 +`define REG_DBG_DATA 19 +`define REG_DBG_CTL 20 + +`define DBG_CTL_SEND 1 +`define DBG_CTL_NEXT 2 diff --git a/hdl/rtl/dsi_core/dsi_fifo.v b/hdl/rtl/dsi_core/dsi_fifo.v new file mode 100644 index 0000000..802e72a --- /dev/null +++ b/hdl/rtl/dsi_core/dsi_fifo.v @@ -0,0 +1,128 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`timescale 1ns/1ns + +/* + * dsi_fifo.v + * + * Simple synchronous FIFO. + */ + +module dsi_fifo + #( + parameter g_width = 32, + parameter g_size = 1024 + ) ( + input clk_i, + input rst_n_i, + + input [g_width-1:0] d_i, + input we_i, + output full_o, + + output reg [g_width-1:0] q_o, + input rd_i, + output empty_o + ); + function integer CLogB2; + input [31:0] Depth; + integer i; + begin + i = Depth; + for(CLogB2 = 0; i > 0; CLogB2 = CLogB2 + 1) + i = i >> 1; + end + endfunction // for + + localparam c_bits = CLogB2(g_size) - 1; + + reg [c_bits-1:0] rd_ptr, wr_ptr; + reg [c_bits:0] usedw; + + wire [c_bits-1:0] mem_rd_addr; + reg full, empty; + reg guard_bit; + + always@(posedge clk_i) + if(!rst_n_i) + begin + rd_ptr <= 0; + wr_ptr <= 0; + end else begin + if(we_i && !full) + wr_ptr<=wr_ptr+1; + if(rd_i && !empty) + rd_ptr<=rd_ptr+1; + end + + + always@(posedge clk_i) + if(!rst_n_i) + usedw <= 0; + else begin + if (we_i && !rd_i && !full) + usedw<=usedw+1; + else if (!we_i && rd_i &&!empty) + usedw <= usedw - 1; + end + + always@(posedge clk_i) + if(!rst_n_i) + begin + full <= 0; + empty <= 1; + end else begin + if (usedw == 1 && rd_i && !we_i) + empty <= 1; + else if(we_i && !rd_i) + empty <= 0; + + if(usedw == g_size-2 && we_i && !rd_i) + full <= 1; + else if(usedw == g_size-1 && rd_i && !we_i) + full <= 0; + end // else: !if(!rst_n_i) + + + assign full_o = full; + assign empty_o = empty; + + reg [g_width-1:0] mem[0:g_size-1]; + + assign mem_rd_addr = rd_i ? rd_ptr : (rd_ptr - 1); + + always@(posedge clk_i) + begin + q_o <= mem[mem_rd_addr]; + if(we_i) + mem[wr_ptr] <= d_i; + end + + // synthesis translate_off + initial begin : init_contents + integer i; + + for(i=0;i + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`timescale 1ns/1ps + +/* + * dsi_packer.v + * + * A module that tightly packs bytes or byte sequences in to an output word of certain + * size. + */ + +module dsi_byte_reverse + ( + d_i, + q_o); + parameter g_num_bytes = 4; + + input [g_num_bytes * 8 - 1 : 0] d_i; + output [g_num_bytes * 8 - 1 : 0] q_o; + + generate + genvar i, j; + for(i=0;i<8;i=i+1) + for(j=0;j g_output_bytes ? g_input_bytes : g_output_bytes) + 2; + + + input clk_i, rst_n_i; + input [g_input_bytes * 8 - 1 : 0] d_i; + input [3 : 0] d_size_i; + output d_req_o; + input d_valid_i, q_flush_i; + + output [g_output_bytes * 8 -1 :0] q_o; + output reg [g_output_bytes-1:0] q_valid_o; + output d_empty_o; + + input q_req_i; + + wire [g_input_bytes * 8 - 1 : 0] d_in; + reg [g_output_bytes * 8 - 1 : 0] q_out; + + reg [4:0] count, avail, avail_next; + reg [c_shiftreg_bytes * 8 -1 :0] shreg; + wire [c_shiftreg_bytes * 8 -1 :0] in_shifted; + wire shift_out; + wire [4:0] in_shift; + + wire d_req_int; + + + assign shift_out = (count >= g_output_bytes && q_req_i); + assign in_shift = (shift_out ? count - g_output_bytes : count); + + + dsi_byte_swapper #(g_input_bytes) U_RevIn ( d_i, d_size_i, d_in ); + dsi_byte_reverse #(g_output_bytes) U_RevOut ( q_out, q_o ); + + + + dsi_byte_shifter + #( + .g_data_bytes(g_input_bytes), + .g_max_shift(c_shiftreg_bytes - 1) + ) + U_Shifter + ( + .d_i(d_in), + .shift_i(in_shift), + .shifted_o(in_shifted) + ); + + + always@(posedge clk_i) + if(!rst_n_i) begin + q_valid_o <= 0; + q_out <= 0; + end else if(shift_out || q_flush_i) + begin : drive_output + integer i; + + q_out <= shreg[g_output_bytes * 8 - 1 : 0]; + for(i=0;i i; + end else + q_valid_o <= 0; + + + always@(posedge clk_i) + if (!rst_n_i) + begin + count <= 0; + avail <= c_shiftreg_bytes; + shreg <= 0; + + end else begin + if(d_valid_i && shift_out) begin + shreg <= (shreg >> ( 8 * g_output_bytes )) | in_shifted; + count <= count - g_output_bytes + d_size_i; + end else if(d_valid_i) begin + shreg <= shreg | in_shifted; + count <= count + d_size_i; + end else if(shift_out) begin + shreg <= (shreg >> ( 8 * g_output_bytes )); + count <= count - g_output_bytes; + end else if (q_flush_i) begin + count <= 0; + shreg <= 0; + end + avail <= avail_next; + end // else: !if(!rst_n_i) + + + always@* + if(d_valid_i && shift_out) + avail_next <= avail + g_output_bytes - d_size_i; + else if(d_valid_i) + avail_next <= avail - d_size_i; + else if(shift_out) + avail_next <= avail + g_output_bytes; + else if(q_flush_i) + avail_next <= c_shiftreg_bytes; + else + avail_next <= avail; + + + assign d_req_int = (avail_next >= g_input_bytes) || (shift_out && avail_next >= (g_input_bytes - g_output_bytes)); + assign d_req_o = d_req_int; + assign d_empty_o = !count; + + +endmodule // dsi_packer + + + diff --git a/hdl/rtl/dsi_core/dsi_packet_assembler.v b/hdl/rtl/dsi_core/dsi_packet_assembler.v new file mode 100644 index 0000000..829655e --- /dev/null +++ b/hdl/rtl/dsi_core/dsi_packet_assembler.v @@ -0,0 +1,264 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + + +`include "dsi_defs.vh" + +`timescale 1ns/1ps + +/* + * dsi_packet_assembler.v + * + * Puts together DSI packets and produces a packed data stream for the PHY. + */ + +module dsi_packet_assembler + ( + clk_i, + rst_n_i, + p_req_i, + p_islong_i, + p_type_i, + p_wcount_i, + p_command_i, + p_payload_i, + p_dreq_o, + p_dlast_o, + p_last_i, + + phy_d_o, + phy_dvalid_o, + phy_hs_request_o, + phy_hs_dreq_i + ); + + parameter g_bytes_per_clock = 1; + parameter g_num_lanes = 3; + + input clk_i; + input rst_n_i; + + input p_req_i; + input p_islong_i; + input [5:0] p_type_i; + input [15:0] p_wcount_i; + input [15:0] p_command_i; + input [g_bytes_per_clock * 24-1:0] p_payload_i; + input p_last_i; + + output p_dreq_o; + output p_dlast_o; + output [g_num_lanes*8-1:0] phy_d_o; + output [g_num_lanes-1:0] phy_dvalid_o; + + output phy_hs_request_o; + input phy_hs_dreq_i; + +`define ST_LP_MODE 3 +`define ST_IDLE 0 +`define ST_PAYLOAD 1 +`define ST_CRC 2 + + reg [3:0] state; + reg [15:0] tx_count; + wire [15:0] tx_count_next; + + reg [31:0] pack_data; + wire pack_req; + reg pack_req_d0; + + reg [3:0] pack_size; + reg pack_valid; + wire pack_empty; + reg pack_flush; + wire [g_num_lanes-1:0] pack_qvalid; + + assign tx_count_next = tx_count - 3; + + dsi_packer + #( + .g_input_bytes(4*g_bytes_per_clock), + .g_output_bytes(g_num_lanes) + ) + U_Packer + ( + .clk_i(clk_i), + .rst_n_i(rst_n_i), + + .d_i(pack_data), + .d_size_i(pack_size), + .d_req_o(pack_req), + .d_valid_i(pack_valid), + .d_empty_o(pack_empty), + + .q_o(phy_d_o), + .q_req_i(phy_hs_dreq_i), + .q_valid_o(pack_qvalid), + .q_flush_i(pack_flush) + ); + + + reg crc_reset,crc_valid; + wire [15:0] crc_value; + reg [2:0] crc_nbytes = 3; + + dsi_crc + #( + .g_max_data_bytes(3) + ) + U_CRC + ( + .clk_i(clk_i), + .rst_i(crc_reset), + .valid_i(crc_valid), + .nbytes_i(crc_nbytes), + .d_i(p_payload_i), + .crc_o(crc_value) + ); + + + reg [23:0] pack_header; + wire [23:0] pack_header_swapped; + + wire [7:0] ecc_value; + + always @* + if(p_islong_i) + pack_header <= { 2'b00, p_type_i, p_wcount_i[7:0], p_wcount_i[15:8] }; + else + pack_header <= { 2'b00, p_type_i, p_command_i[7:0], p_command_i[15:8] }; + + assign pack_header_swapped [7:0] = pack_header[23:16]; + assign pack_header_swapped [15:8] = pack_header[15:8]; + assign pack_header_swapped [23:16] = pack_header[7:0]; + + + dsi_parity U_ECC + ( + .d_i(pack_header_swapped), + .p_o(ecc_value) + ); + + + always @* + begin + crc_valid <= (state == `ST_PAYLOAD ? pack_req_d0 : 0); + crc_reset <= (state == `ST_IDLE ? 1: 0 ); + end + + assign p_idle_o = (state == `ST_IDLE || state == `ST_LP_MODE); + + always@(posedge clk_i) + pack_req_d0 <= pack_req; + + + always@(posedge clk_i) + if(!rst_n_i) begin + state <= `ST_LP_MODE; + end else begin + case (state) + `ST_LP_MODE: + if(p_req_i && pack_req_d0 && phy_hs_dreq_i) begin + state <= `ST_IDLE; + end + + `ST_IDLE: begin + tx_count <=0; + + if(p_req_i && pack_req_d0) begin + + tx_count <= p_wcount_i; + + if(p_islong_i) + state <= `ST_PAYLOAD; + else begin + if(p_last_i) + state <= `ST_LP_MODE; + else + state <= `ST_IDLE; + end + end else if(!p_req_i) + state <= `ST_LP_MODE; + + end // case: `ST_IDLE + + `ST_PAYLOAD: + if(pack_req_d0) + begin + tx_count <= tx_count_next; + + if(!tx_count_next) + state <= `ST_CRC; + else if(!p_req_i) + state <= `ST_LP_MODE; + end + + `ST_CRC: + if(pack_req_d0) begin + state <= `ST_IDLE; + end + endcase // case (state) + end // else: !if(!rst_n_i) + + always@* + begin + case (state) + `ST_LP_MODE: begin + pack_data <= { g_num_lanes{`DSI_SYNC_SEQ} }; + pack_size <= g_num_lanes; + pack_valid <= pack_req_d0 && p_req_i && phy_hs_dreq_i; + pack_flush <= ~p_req_i; + end + + `ST_IDLE: begin + pack_data <= {pack_header, ecc_value}; + pack_size <= 4; + pack_valid <= pack_req_d0; + pack_flush <= 0; + end + + `ST_PAYLOAD: begin + pack_data <= p_payload_i; + pack_size <= g_bytes_per_clock * 3; + pack_valid <= pack_req_d0; + pack_flush <= 0; + end + + `ST_CRC: begin + pack_data <= {crc_value[7:0], crc_value[15:8]}; + pack_size <= 2; + pack_valid <= pack_req_d0; + pack_flush <= ~p_req_i; + end + + default: begin + pack_flush <= 0; + pack_data <= 0; + pack_size <= g_num_lanes; + pack_valid <= 0; + end + endcase // case (state) + end + + assign phy_hs_request_o = p_req_i || (state != `ST_LP_MODE) || !pack_empty; + assign phy_dvalid_o = pack_qvalid; + assign p_dreq_o = (pack_req && p_req_i && phy_hs_dreq_i && !(state == `ST_PAYLOAD && !tx_count_next)); + +endmodule // dsi_packet_assembler + + diff --git a/hdl/rtl/dsi_core/dsi_test_image_gen.v b/hdl/rtl/dsi_core/dsi_test_image_gen.v new file mode 100644 index 0000000..a8583a9 --- /dev/null +++ b/hdl/rtl/dsi_core/dsi_test_image_gen.v @@ -0,0 +1,185 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`include "dsi_defs.vh" + +`timescale 1ns/1ns + +/* + * dsi_test_image_gen.v + * + * A simple color bar image generator. + */ + +module dsi_test_image_gen + ( + input clk_i, + input rst_n_i, + + input fifo_full_i, + output fifo_frame_o, + output [23:0] fifo_pixel_o, + output fifo_we_o, + + input [5:0] host_a_i, + input [31:0] host_d_i, + output [31:0] host_d_o, + input host_wr_i, + + output test_enable_o + ); + + parameter g_use_dpram = 1; + parameter g_fb_size = 640 * 960 / 2; + parameter g_fb_base = 32'h08000000; + parameter g_fb_mask = 32'h0f000000; + + reg [11:0] r_xsize; + reg [11:0] r_ysize; + reg r_enable; + + reg [11:0] x, y; + + wire fifo_we; + reg [3:0] framebuffer [ 0:g_fb_size-1 ]; + + // synthesis translate_off + initial begin: init_ram + integer i; + for(i=0;i + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`timescale 1ns/1ps + +`include "dsi_defs.vh" + +/* + * dsi_timing_gen.v + * + * Image timing generator - produces the display refresh timing (hsync, vsync, blanking, etc.) + * The image is delivered by a simple FIFO interface, pixel-by-pixel. The output requests + * particular packets from the Packet Assembler. + */ + +module dsi_timing_gen + ( + clk_i, + rst_n_i, + + fifo_empty_i, + fifo_rd_o, + fifo_pixels_i, + fifo_frame_i, + fifo_got_frame_i, + p_req_o, + p_islong_o, + p_type_o, + p_wcount_o, + p_command_o, + p_payload_o, + p_dreq_i, + p_last_o, + + host_a_i, + host_d_i, + host_d_o, + host_wr_i + ); + + parameter g_pixels_per_clock = 1; + + localparam g_pixel_width = g_pixels_per_clock * 24; + + input clk_i; + input rst_n_i; + + input fifo_empty_i; + input fifo_got_frame_i; + + output fifo_rd_o; + input [g_pixel_width - 1: 0] fifo_pixels_i; + input fifo_frame_i; + + output reg p_req_o, p_islong_o; + output reg [5:0] p_type_o; + output reg [15:0] p_wcount_o, p_command_o; + output [g_pixel_width-1:0] p_payload_o; + + input p_dreq_i; + + output reg p_last_o; + + input [3:0] host_a_i; + input [31:0] host_d_i; + output reg [31:0] host_d_o; + input host_wr_i; + + +`define ST_BPORCH 0 +`define ST_FPORCH 1 +`define ST_HSYNC_START 2 +`define ST_HSYNC_END 3 +`define ST_HSYNC_ACTIVE 4 +`define ST_LINE 6 +`define ST_VSYNC_PACKET 7 +`define ST_STOP 8 +`define ST_LONG_PACKET 9 +`define ST_LP 10 + + + + + reg [3:0] state, next_state; + + reg [11:0] h_count, v_count; + + reg [11:0] h_front_porch, h_back_porch, h_active, h_total; + reg [11:0] v_front_porch, v_back_porch, v_active, v_total; + + reg enable = 0; + reg disp_en_mask; + + reg [11:0] pixel_counter; + + + // host registers + always@(posedge clk_i) + if(!rst_n_i) + begin + enable <= 0; + end else if(host_wr_i) begin + case (host_a_i) + 0:h_front_porch <= host_d_i; + 1:h_back_porch <= host_d_i; + 2:h_active <= host_d_i; + 3:h_total <= host_d_i; + 4:v_front_porch <= host_d_i; + 5:v_back_porch <= host_d_i; + 6:v_active <= host_d_i; + 7:v_total <= host_d_i; + 8:enable<=host_d_i[0]; + endcase // case (host_a_i) + end + + task send(input long, input [5:0] ptype, input [15:0] count, input[3:0] _next_state, input is_last); + begin + if(p_dreq_i) begin + p_islong_o <= long; + p_type_o <= ptype; + p_wcount_o <= count; + p_command_o <= 0; + p_last_o <= is_last; + + pixel_counter <= count; + if(long) + state <= `ST_LONG_PACKET; + else + state <= _next_state; + + next_state <= _next_state; + end // if (p_dreq_i) + end + endtask // send + + reg push_pixels, push_pixels_d0; + + always@(posedge clk_i) + if(!rst_n_i || !enable) begin + v_count <= 0; + state <= `ST_LP; + pixel_counter <= h_total; + p_req_o <= 0; + p_last_o <= 0; + + disp_en_mask <= 0; + push_pixels <= 0; + push_pixels_d0 <= 0; + end else begin + push_pixels_d0 <= push_pixels; + + case (state) + `ST_FPORCH: + begin + push_pixels<=0; + push_pixels_d0<=0; + + if(v_count == v_back_porch) begin + disp_en_mask <= 1; + end else if(v_count == v_front_porch) begin + disp_en_mask <= 0; + end + + send(1, `PTYPE_BLANKING, h_front_porch, `ST_HSYNC_START, 0); + end // case: `ST_FPORCH + + `ST_HSYNC_START: begin + p_req_o <= 1; + + if(v_count == 0) + send(0, `PTYPE_VSYNC_START, h_total, `ST_BPORCH, 0); + else if (v_count == v_total) + send(0, `PTYPE_HSYNC_START, h_total, `ST_LP, 1); + else + send(0, `PTYPE_HSYNC_START, h_total, `ST_BPORCH, 0); + end + + `ST_BPORCH: + send(1, `PTYPE_BLANKING, h_back_porch, `ST_LINE, 0); + + `ST_LINE: + begin + send(1, disp_en_mask ? `PTYPE_RGB24: `PTYPE_BLANKING, h_active, `ST_FPORCH, 0); + if(p_dreq_i) begin + if(v_count == v_total) + v_count <= 0; + else + v_count <= v_count + 1; + push_pixels <= disp_en_mask; + end + end + + `ST_LP: begin + p_req_o <= 0; + if(pixel_counter == 0) begin + if(!fifo_empty_i) begin + state <= `ST_HSYNC_START; + v_count <= 0; + end + end else + pixel_counter <= pixel_counter - 1; + end + + `ST_LONG_PACKET: + begin + if(p_dreq_i) + pixel_counter <= pixel_counter - 3; + if(pixel_counter == 3) + begin + push_pixels <=0; + state <= next_state; + end + end + + endcase // case (state) + end // else: !if(!rst_n_i || !enable) + + assign fifo_rd_o = (push_pixels && p_dreq_i); + assign p_payload_o = (push_pixels || push_pixels_d0 ? fifo_pixels_i : 0); + +endmodule // dsi_timing_gen + diff --git a/hdl/rtl/dsi_core/dsi_utils.v b/hdl/rtl/dsi_core/dsi_utils.v new file mode 100644 index 0000000..324c6dd --- /dev/null +++ b/hdl/rtl/dsi_core/dsi_utils.v @@ -0,0 +1,109 @@ +/* + * DSI Core + * Copyright (C) 2013 twl + * + * This library 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 3.0 of the License, or (at your option) any later version. + * + * This library 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 library. + */ + +`timescale 1ns/1ps + +/* + * dsi_utils.v + * + * Some utility stuff (parity/CRC generators) + */ + +module dsi_parity + ( + input [23:0] d_i, + output [7:0] p_o + ); + + assign p_o[0]=^{d_i[2:0], d_i[5:4], d_i[7], d_i[11:10], d_i[13], d_i[16], d_i[23:20]}; + assign p_o[1]=^{d_i[1:0], d_i[4:3], d_i[6], d_i[8], d_i[10], d_i[12], d_i[14], d_i[17], d_i[23:20]}; + assign p_o[2]=^{d_i[0], d_i[3:2], d_i[6:5], d_i[9], d_i[12:11], d_i[15], d_i[18], d_i[22:20] }; + assign p_o[3]=^{d_i[3:1], d_i[9:7], d_i[15:13], d_i[21:19], d_i[23]}; + assign p_o[4]=^{d_i[9:4], d_i[20:16], d_i[23:22]}; + assign p_o[5]=^{d_i[19:10], d_i[23:21]}; + assign p_o[7:6]=2'b0; +endmodule // dsi_parity + +module dsi_crc_comb (input[15:0] crc, input[7:0] x, output [15:0] crc_new); + assign crc_new[0] = crc[8] ^ crc[12] ^ x[7-0] ^ x[7-4]; + assign crc_new[1] = crc[9] ^ crc[13] ^ x[7-1] ^ x[7-5]; + assign crc_new[2] = crc[10] ^ crc[14] ^ x[7-2] ^ x[7-6]; + assign crc_new[3] = crc[11] ^ crc[15] ^ x[7-3] ^ x[7-7]; + assign crc_new[4] = crc[12] ^ x[7-4]; + assign crc_new[5] = crc[8] ^ crc[12] ^ crc[13] ^ x[7-0] ^ x[7-4] ^ x[7-5]; + assign crc_new[6] = crc[9] ^ crc[13] ^ crc[14] ^ x[7-1] ^ x[7-5] ^ x[7-6]; + assign crc_new[7] = crc[10] ^ crc[14] ^ crc[15] ^ x[7-2] ^ x[7-6] ^ x[7-7]; + assign crc_new[8] = crc[0] ^ crc[11] ^ crc[15] ^ x[7-3] ^ x[7-7]; + assign crc_new[9] = crc[1] ^ crc[12] ^ x[7-4]; + assign crc_new[10] = crc[2] ^ crc[13] ^ x[7-5]; + assign crc_new[11] = crc[3] ^ crc[14] ^ x[7-6]; + assign crc_new[12] = crc[4] ^ crc[8] ^ crc[12] ^ crc[15] ^ x[7-0] ^ x[7-4] ^ x[7-7]; + assign crc_new[13] = crc[5] ^ crc[9] ^ crc[13] ^ x[7-1] ^ x[7-5]; + assign crc_new[14] = crc[6] ^ crc[10] ^ crc[14] ^ x[7-2] ^ x[7-6]; + assign crc_new[15] = crc[7] ^ crc[11] ^ crc[15] ^ x[7-3] ^ x[7-7]; +endmodule // dsi_crc_comb + + +module dsi_crc + ( + clk_i, + rst_i, + valid_i, + nbytes_i, + d_i, + crc_o); + + parameter g_max_data_bytes = 3; + + input [g_max_data_bytes*8-1:0] d_i; + input valid_i; + input [2:0] nbytes_i; + input clk_i; + input rst_i; + output [15:0] crc_o; + + reg [15:0] crc_cur; + + wire [15:0] stages_in [0:g_max_data_bytes-1]; + wire [15:0] stages_out [0:g_max_data_bytes-1]; + + generate + genvar i ; + for(i=0;i + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/hdl/top/spec/Manifest.py b/hdl/top/spec/Manifest.py new file mode 100644 index 0000000..fbacd69 --- /dev/null +++ b/hdl/top/spec/Manifest.py @@ -0,0 +1,8 @@ +files = ["spec_top.vhd", "spec_top.ucf", "spec_reset_gen.vhd", "dsi_pll_spartan6.v"] + +fetchto = "../../ip_cores" + +modules = { + "local" : ["../../rtl/dsi_core" ], + "git" : [ "git://ohwr.org/hdl-core-lib/general-cores.git" ] + } diff --git a/hdl/top/spec/dsi_pll_spartan6.v b/hdl/top/spec/dsi_pll_spartan6.v new file mode 100644 index 0000000..0dec59a --- /dev/null +++ b/hdl/top/spec/dsi_pll_spartan6.v @@ -0,0 +1,142 @@ +// file: dsi_pll_spartan6.v +// +// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// "Output Output Phase Duty Pk-to-Pk Phase" +// "Clock Freq (MHz) (degrees) Cycle (%) Jitter (ps) Error (ps)" +//---------------------------------------------------------------------------- +// CLK_OUT1___255.000______0.000______50.0______200.079____379.637 +// CLK_OUT2____31.875______0.000______50.0______272.567____379.637 +// +//---------------------------------------------------------------------------- +// "Input Clock Freq (MHz) Input Jitter (UI)" +//---------------------------------------------------------------------------- +// __primary______________20____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "dsi_pll_spartan6,clk_wiz_v3_2,{component_name=dsi_pll_spartan6,use_phase_alignment=false,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=PLL_BASE,num_out_clk=2,clkin1_period=50.000,clkin2_period=50.000,use_power_down=false,use_reset=false,use_locked=true,use_inclk_stopped=false,use_status=false,use_freeze=false,use_clk_valid=false,feedback_type=SINGLE,clock_mgr_type=MANUAL,manual_override=false}" *) +module dsi_pll_spartan6 + (// Clock in ports + input clk_in_i, + // Clock out ports + output clk_phy_o, + output clk_sys_o, + // Status and control signals + output locked_o + ); + + // Input buffering + //------------------------------------ + IBUFG clkin1_buf + (.O (clkin1), + .I (clk_in_i)); + + + // Clocking primitive + //------------------------------------ + // Instantiation of the PLL primitive + // * Unused inputs are tied off + // * Unused outputs are labeled unused + wire [15:0] do_unused; + wire drdy_unused; + wire clkfbout; + wire clkout2_unused; + wire clkout3_unused; + wire clkout4_unused; + wire clkout5_unused; + + PLL_BASE + #(.BANDWIDTH ("OPTIMIZED"), + .CLK_FEEDBACK ("CLKFBOUT"), + .COMPENSATION ("INTERNAL"), + .DIVCLK_DIVIDE (1), + .CLKFBOUT_MULT (51), + .CLKFBOUT_PHASE (0.000), + .CLKOUT0_DIVIDE (4), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT1_DIVIDE (32), + .CLKOUT1_PHASE (0.000), + .CLKOUT1_DUTY_CYCLE (0.500), + .CLKIN_PERIOD (50.000), + .REF_JITTER (0.010)) + pll_base_inst + // Output clocks + (.CLKFBOUT (clkfbout), + .CLKOUT0 (clkout0), + .CLKOUT1 (clkout1), + .CLKOUT2 (clkout2_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + // Status and control signals + .LOCKED (locked_o), + .RST (1'b0), + // Input clock control + .CLKFBIN (clkfbout), + .CLKIN (clkin1)); + + + // Output buffering + //----------------------------------- + + assign clk_phy_o = clkout0; + + BUFG clkout2_buf + (.O (clk_sys_o), + .I (clkout1)); + + + +endmodule diff --git a/hdl/top/spec/spec_reset_gen.vhd b/hdl/top/spec/spec_reset_gen.vhd new file mode 100644 index 0000000..23aa09e --- /dev/null +++ b/hdl/top/spec/spec_reset_gen.vhd @@ -0,0 +1,55 @@ +library ieee; +use ieee.STD_LOGIC_1164.all; +use ieee.NUMERIC_STD.all; + +use work.gencores_pkg.all; + +entity spec_reset_gen is + + port ( + clk_sys_i : in std_logic; + + rst_pcie_n_a_i : in std_logic; + rst_button_n_a_i : in std_logic; + + rst_n_o : out std_logic + ); + +end spec_reset_gen; + +architecture behavioral of spec_reset_gen is + + signal powerup_cnt : unsigned(7 downto 0) := x"00"; + signal button_synced_n : std_logic; + signal pcie_synced_n : std_logic; + signal powerup_n : std_logic := '0'; + +begin -- behavioral + + U_EdgeDet_PCIe : gc_sync_ffs port map ( + clk_i => clk_sys_i, + rst_n_i => '1', + data_i => rst_pcie_n_a_i, + ppulse_o => pcie_synced_n); + + U_Sync_Button : gc_sync_ffs port map ( + clk_i => clk_sys_i, + rst_n_i => '1', + data_i => rst_button_n_a_i, + synced_o => button_synced_n); + + p_powerup_reset : process(clk_sys_i) + begin + if rising_edge(clk_sys_i) then + if(powerup_cnt /= x"ff") then + powerup_cnt <= powerup_cnt + 1; + powerup_n <= '0'; + else + powerup_n <= '1'; + end if; + end if; + end process; + + rst_n_o <= powerup_n and button_synced_n and (not pcie_synced_n); + +end behavioral; diff --git a/hdl/top/spec/spec_top.ucf b/hdl/top/spec/spec_top.ucf new file mode 100644 index 0000000..be8a0b4 --- /dev/null +++ b/hdl/top/spec/spec_top.ucf @@ -0,0 +1,90 @@ +NET "CLK_20M_I" LOC = H12; +NET "CLK_20M_I" IOSTANDARD = "LVCMOS25"; + +NET "uart_rxd_i" LOC= A2; +NET "uart_rxd_i" IOSTANDARD=LVCMOS25; + +NET "uart_txd_o" LOC= B2; +NET "uart_txd_o" IOSTANDARD=LVCMOS25; + +NET "button1_n_i" LOC = C22; +NET "button1_n_i" IOSTANDARD = "LVCMOS18"; +#Created by Constraints Editor (xc6slx45t-fgg484-3) - 2013/06/07 +NET "clk_20m_i" TNM_NET = clk_20m_i; +TIMESPEC TS_clk_20m_i = PERIOD "clk_20m_i" 20 MHz HIGH 50 %; + +NET "dsi_clk_p_o" LOC = V11; +#15_p +NET "dsi_clk_n_o" LOC = W11; +#15_n +NET "dsi_hs_p_o[0]" LOC = Y16; +#30_p +NET "dsi_hs_n_o[0]" LOC = W15; +#30_n +NET "dsi_hs_p_o[1]" LOC = V13; +#24_p +NET "dsi_hs_n_o[1]" LOC = W13; +#24_n +NET "dsi_hs_p_o[2]" LOC = U9; +#07p +NET "dsi_hs_n_o[2]" LOC = V9; +#07n + +#NET "dsi_hs_p_o[3]" LOC = V17; +#07p +#NET "dsi_hs_n_o[3]" LOC = W18; +#07n + +NET "dsi_lp_p_o[0]" LOC = Y14; +#28_n +NET "dsi_lp_p_o[0]" IOSTANDARD="LVCMOS25"; + +NET "dsi_lp_n_o[0]" LOC = V17; +#32_p +NET "dsi_lp_n_o[0]" IOSTANDARD="LVCMOS25"; + +NET "dsi_lp_p_o[1]" LOC = AB15; +#21_n +NET "dsi_lp_p_o[1]" IOSTANDARD="LVCMOS25"; + +NET "dsi_lp_n_o[1]" LOC = W14; +#28_p +NET "dsi_lp_n_o[1]" IOSTANDARD="LVCMOS25"; + +NET "dsi_lp_p_o[2]" LOC = T8; +#4_n +NET "dsi_lp_p_o[2]" IOSTANDARD="LVCMOS25"; + +NET "dsi_lp_n_o[2]" LOC = W10; +#11_p +NET "dsi_lp_n_o[2]" IOSTANDARD="LVCMOS25"; + +#NET "dsi_lp_p_o[3]" LOC = A20; +#4_n +#NET "dsi_lp_p_o[3]" IOSTANDARD="LVCMOS25"; + +#NET "dsi_lp_n_o[3]" LOC = AA18; +#11_p +#NET "dsi_lp_n_o[3]" IOSTANDARD="LVCMOS25"; + + +NET "dsi_clk_lp_p_o" LOC = Y10; +#11_n +NET "dsi_clk_lp_p_o" IOSTANDARD="LVCMOS25"; + +NET "dsi_clk_lp_n_o" LOC = Y15; +#19_p +NET "dsi_clk_lp_n_o" IOSTANDARD="LVCMOS25"; + +NET "dsi_resetb_o" LOC = F16; +#04_p +NET "dsi_resetb_o" IOSTANDARD="LVCMOS25"; + + +NET "dsi_hifa_o" LOC = E16; +#02_n +NET "dsi_hifa_o" IOSTANDARD="LVCMOS25"; + +NET "dsi_pifa_o" LOC = W6; +#02_p +NET "dsi_pifa_o" IOSTANDARD="LVCMOS25"; diff --git a/hdl/top/spec/spec_top.vhd b/hdl/top/spec/spec_top.vhd new file mode 100644 index 0000000..a2a2642 --- /dev/null +++ b/hdl/top/spec/spec_top.vhd @@ -0,0 +1,259 @@ +library ieee; +use ieee.std_logic_1164.all; + +use work.wishbone_pkg.all; + +entity spec_top is + + port ( + clk_20m_i : in std_logic; + + button1_n_i : in std_logic := 'H'; + + uart_txd_o : out std_logic; + uart_rxd_i : in std_logic; + +------------------------------------------------------------------------------- +-- DSI ports +------------------------------------------------------------------------------- + + dsi_clk_p_o : out std_logic; + dsi_clk_n_o : out std_logic; + + dsi_clk_lp_p_o : out std_logic; + dsi_clk_lp_n_o : out std_logic; + + dsi_hs_p_o : out std_logic_vector(2 downto 0); + dsi_hs_n_o : out std_logic_vector(2 downto 0); + + dsi_lp_p_o : out std_logic_vector(2 downto 0); + dsi_lp_n_o : out std_logic_vector(2 downto 0); + + dsi_resetb_o : out std_logic; + dsi_hifa_o : out std_logic; + dsi_pifa_o : out std_logic + ); + +end spec_top; + +architecture rtl of spec_top is + + component dsi_core is + generic( + g_pixels_per_clock : integer := 1; + g_lanes : integer := 3; + g_fifo_size : integer := 1024; + g_invert_lanes : integer := 7; + g_invert_clock : integer := 1); + port( + clk_sys_i : in std_logic; + clk_phy_i : in std_logic; + + rst_n_i : in std_logic; + + pll_locked_i : in std_logic; + + frame_ready_o : out std_logic; + + fifo_full_o : out std_logic; + fifo_pixels_i : in std_logic_vector (24 * g_pixels_per_clock-1 downto 0) := (others => '0'); + fifo_frame_i : in std_logic; + fifo_wr_i : in std_logic; + + dsi_clk_p_o : out std_logic; + dsi_clk_n_o : out std_logic; + dsi_clk_lp_p_o : out std_logic; + dsi_clk_lp_n_o : out std_logic; + dsi_clk_lp_oe_o : out std_logic; + + dsi_hs_p_o : out std_logic_vector(g_lanes-1 downto 0); + dsi_hs_n_o : out std_logic_vector(g_lanes-1 downto 0); + + dsi_lp_p_o : out std_logic_vector(g_lanes-1 downto 0); + dsi_lp_n_o : out std_logic_vector(g_lanes-1 downto 0); + + + dsi_lp_oe_o : out std_logic_vector(g_lanes-1 downto 0); + + dsi_reset_n_o : out std_logic; + + host_a_i : in std_logic_vector(5 downto 0); + host_d_i : in std_logic_vector(31 downto 0); + host_d_o : out std_logic_vector(31 downto 0); + host_wr_i : in std_logic + ); + end component; + + component dsi_pll_spartan6 + port ( + clk_in_i : in std_logic; + clk_sys_o : out std_logic; + clk_phy_o : out std_logic; + locked_o : out std_logic); + end component; + + component spec_reset_gen + port ( + clk_sys_i : in std_logic; + rst_pcie_n_a_i : in std_logic; + rst_button_n_a_i : in std_logic; + rst_n_o : out std_logic); + end component; + + constant c_cnx_slave_ports : integer := 1; + constant c_cnx_master_ports : integer := 3; + + constant c_master_cpu_i : integer := 0; + + constant c_slave_dpram : integer := 0; + constant c_slave_uart : integer := 1; + constant c_slave_dsi : integer := 2; + + signal cnx_slave_in : t_wishbone_slave_in_array(c_cnx_slave_ports-1 downto 0); + signal cnx_slave_out : t_wishbone_slave_out_array(c_cnx_slave_ports-1 downto 0); + + signal cnx_master_in : t_wishbone_master_in_array(c_cnx_master_ports-1 downto 0); + signal cnx_master_out : t_wishbone_master_out_array(c_cnx_master_ports-1 downto 0); + + constant c_cfg_base_addr : t_wishbone_address_array(c_cnx_master_ports-1 downto 0) := + (0 => x"00000000", -- 64KB of fpga memory + 1 => x"00010000", -- The second port to the same memory + 2 => x"00020000"); -- Peripherals + + constant c_cfg_base_mask : t_wishbone_address_array(c_cnx_master_ports-1 downto 0) := + (0 => x"000f0000", + 1 => x"000f0000", + 2 => x"000f0000"); + + signal cpu_iwb_out : t_wishbone_master_out; + signal cpu_iwb_in : t_wishbone_master_in; + + signal rst_n, clk_phy, clk_sys, pll_locked, pll_locked_n, dsi_wr : std_logic; + signal dsi_lp_p_int, dsi_lp_n_int, dsi_lp_oe : std_logic_vector(2 downto 0); + signal dsi_clk_lp_p, dsi_clk_lp_n, dsi_clk_lp_oe : std_logic; + +begin -- rtl + + U_PLL : dsi_pll_spartan6 + port map ( + clk_in_i => clk_20m_i, + clk_sys_o => clk_sys, + clk_phy_o => clk_phy, + locked_o => pll_locked); + + pll_locked_n <= not pll_locked; + + U_Reset_Gen : spec_reset_gen + port map ( + clk_sys_i => clk_sys, + rst_pcie_n_a_i => pll_locked_n, + rst_button_n_a_i => button1_n_i, + rst_n_o => rst_n); + + U_CPU : xwb_lm32 + generic map ( + g_profile => "medium") + port map ( + clk_sys_i => clk_sys, + rst_n_i => rst_n, + irq_i => x"00000000", + dwb_o => cnx_slave_in(0), + dwb_i => cnx_slave_out(0), + iwb_o => cpu_iwb_out, + iwb_i => cpu_iwb_in); + + U_Intercon : xwb_crossbar + generic map ( + g_num_masters => c_cnx_slave_ports, + g_num_slaves => c_cnx_master_ports, + g_registered => true, + g_address => c_cfg_base_addr, + g_mask => c_cfg_base_mask) + port map ( + clk_sys_i => clk_sys, + rst_n_i => rst_n, + slave_i => cnx_slave_in, + slave_o => cnx_slave_out, + master_i => cnx_master_in, + master_o => cnx_master_out); + + U_DPRAM : xwb_dpram + generic map ( + g_size => 16384, -- 16kB + g_init_file => "boot.ram", + g_must_have_init_file => true, + g_slave1_interface_mode => PIPELINED, + g_slave2_interface_mode => PIPELINED, + g_slave1_granularity => BYTE, + g_slave2_granularity => BYTE) + port map ( + clk_sys_i => clk_sys, + rst_n_i => rst_n, + slave1_i => cnx_master_out(c_slave_dpram), + slave1_o => cnx_master_in(c_slave_dpram), + slave2_i => cpu_iwb_out, + slave2_o => cpu_iwb_in); + + U_UART : xwb_simple_uart + generic map ( + g_interface_mode => PIPELINED, + g_address_granularity => BYTE) + port map ( + clk_sys_i => clk_sys, + rst_n_i => rst_n, + slave_i => cnx_master_out(c_slave_uart), + slave_o => cnx_master_in(c_slave_uart), + uart_rxd_i => uart_rxd_i, + uart_txd_o => uart_txd_o); + + + U_DSI_Core : dsi_core + port map ( + clk_sys_i => clk_sys, + clk_phy_i => clk_phy, + rst_n_i => rst_n, + pll_locked_i => pll_locked, +-- frame_ready_o => frame_ready_o, + fifo_full_o => open, +-- fifo_pixels_i => x"000000000000", + fifo_frame_i => '0', + fifo_wr_i => '0', + dsi_clk_p_o => dsi_clk_p_o, + dsi_clk_n_o => dsi_clk_n_o, + dsi_clk_lp_n_o => dsi_clk_lp_n, + dsi_clk_lp_p_o => dsi_clk_lp_p, + dsi_clk_lp_oe_o => dsi_clk_lp_oe, + dsi_hs_p_o => dsi_hs_p_o, + dsi_hs_n_o => dsi_hs_n_o, + dsi_lp_p_o => dsi_lp_p_int, + dsi_lp_n_o => dsi_lp_n_int, + dsi_lp_oe_o => dsi_lp_oe, + dsi_reset_n_o => dsi_resetb_o, + host_a_i => cnx_master_out(c_slave_dsi).adr(7 downto 2), + host_d_i => cnx_master_out(c_slave_dsi).dat, + host_d_o => cnx_master_in(c_slave_dsi).dat, + host_wr_i => dsi_wr); + + dsi_wr <= cnx_master_out(c_slave_dsi).stb and cnx_master_out(c_slave_dsi).cyc and cnx_master_out(c_slave_dsi).we; + + gen_lp_tristates : for i in 0 to 2 generate + dsi_lp_p_o(i) <= not dsi_lp_p_int(i) when dsi_lp_oe(i) = '1' else '1'; + dsi_lp_n_o(i) <= not dsi_lp_n_int(i) when dsi_lp_oe(i) = '1' else '1'; + end generate gen_lp_tristates; + + dsi_clk_lp_p_o <= not dsi_clk_lp_p when dsi_clk_lp_oe = '1' else '1'; + dsi_clk_lp_n_o <= not dsi_clk_lp_n when dsi_clk_lp_oe = '1' else '1'; + + process(clk_sys) + begin + if rising_edge(clk_sys) then + cnx_master_in(c_slave_dsi).ack <= cnx_master_out(c_slave_dsi).stb and cnx_master_out(c_slave_dsi).cyc; + end if; + end process; + + cnx_master_in(c_slave_dsi).stall <= '0'; + cnx_master_in(c_slave_dsi).err <= '0'; + + dsi_pifa_o <= '0'; + dsi_hifa_o <= '0'; +end rtl;