initial commit

master
twl 2013-12-22 15:36:11 +01:00
commit 1b595ed568
22 changed files with 3648 additions and 0 deletions

165
LICENSE Normal file
View File

@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
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.

14
README Normal file
View File

@ -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.

4
hdl/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.zip
work
transcript
*.vlf

View File

@ -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"]

View File

@ -0,0 +1,275 @@
/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* 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

View File

@ -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

455
hdl/rtl/dsi_core/dsi_core.v Normal file
View File

@ -0,0 +1,455 @@
/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* 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;i=i+1)
begin
dphy_lane
#(
.g_invert(g_invert_lanes&(1<<i)?1:0)
)
U_LaneX
(
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.tick_i(tick),
.hs_request_i (phy_hs_request),
.hs_data_i (phy_hs_data[ (g_lanes-i) *8-1 -:8]), // >> ((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<g_lanes;i=i+1)
endgenerate
wire clk_lane_ready;
wire dsi_clk_lp_oe;
dphy_lane
#(
.g_invert(g_invert_clock)
) U_ClockLane (
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.tick_i(tick),
.hs_request_i (r_dsi_clk_en),
.hs_data_i (clk_lane_ready ? 8'haa : 8'h00),
.hs_ready_o (clk_lane_ready),
.hs_valid_i(1'b1),
.lp_request_i (1'b0),
.lp_data_i(8'h00),
.lp_valid_i(1'b0),
.lp_ready_o(),
.serdes_data_o(serdes_data[g_lanes*8+:8]),
.lp_txp_o(dsi_clk_lp_p_o),
.lp_txn_o(dsi_clk_lp_n_o),
.lp_oe_o(dsi_clk_lp_oe)
);
assign serdes_oe_lane [g_lanes] = ~dsi_clk_lp_oe;
assign dsi_clk_lp_oe_o = dsi_clk_lp_oe;
generate
genvar gi, gj;
for(gi=0;gi<8;gi=gi+1)
begin
assign serdes_data_interleaved[(g_lanes+1)*gi+g_lanes] = serdes_data[8*g_lanes+gi];
for(gj=0;gj<g_lanes; gj=gj+1)
begin
assign serdes_data_interleaved[(g_lanes+1)*gi+gj] = serdes_data[8*gj+gi];
end
end
endgenerate
dphy_serdes
#(
.sys_w (g_lanes + 1) ,
.dev_w (g_lanes * 8 + 8)
) U_Serdes (
.DATA_OUT_FROM_DEVICE(serdes_data_interleaved),
.DATA_OUT_TO_PINS_P({dsi_clk_p_o, dsi_hs_p_o }),
.DATA_OUT_TO_PINS_N({dsi_clk_n_o, dsi_hs_n_o }),
.CLK_IN(clk_phy_i),
.CLK_DIV_IN(clk_sys_i),
.LOCKED_IN(pll_locked_i),
.CLK_RESET(~rst_n_i),
.IO_RESET(~rst_n_i),
.OE(serdes_oe_lane));
////////////////
// Packet layer
///////////////
wire p_req, p_islong, p_dreq, p_last;
wire [5:0] p_type;
wire [15:0] p_command, p_wcount;
wire [g_pixel_width-1:0] p_payload;
dsi_packet_assembler
#(
.g_num_lanes(g_lanes),
.g_bytes_per_clock(g_pixels_per_clock)
) U_PktAsm (
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.p_req_i(p_req),
.p_islong_i(p_islong),
.p_type_i(p_type),
.p_wcount_i(p_wcount),
.p_command_i(p_command),
.p_dreq_o(p_dreq),
.p_dlast_o(p_dlast),
.p_payload_i(p_payload),
.p_last_i(p_last),
.phy_d_o(phy_hs_data),
.phy_hs_request_o(phy_hs_request),
.phy_hs_dreq_i(phy_hs_ready_lane[0]),
.phy_dvalid_o(phy_hs_valid)
);
////////////////
// Test Screen generator
///////////////
wire fifo_frame_tgen, fifo_wr_tgen;
wire [g_pixel_width-1:0] fifo_pixel_tgen;
wire fifo_empty, fifo_rd;
wire [g_pixel_width:0] fifo_dout;
wire fifo_frame_int, fifo_wr_int, fifo_full_int;
wire [g_pixel_width-1:0] fifo_pixels_int;
wire tgen_enable;
dsi_test_image_gen
U_TestImgGen
(
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.fifo_full_i(fifo_full_int),
.fifo_frame_o(fifo_frame_tgen),
.fifo_pixel_o(fifo_pixel_tgen),
.fifo_we_o(fifo_wr_tgen),
.host_a_i(host_a_i),
.host_d_i(host_d_i),
.host_wr_i(host_wr_i),
.test_enable_o(tgen_enable)
);
assign fifo_frame_int = (tgen_enable ? fifo_frame_tgen : fifo_frame_i);
assign fifo_pixels_int = (tgen_enable ? fifo_pixel_tgen : fifo_pixels_i);
assign fifo_wr_int = (tgen_enable ? fifo_wr_tgen : fifo_wr_i);
assign fifo_full_o = fifo_full_int;
reg fifo_rd_d0, fifo_got_frame;
///////////////
// Image timing
///////////////
dsi_timing_gen U_TimingGen
(
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.fifo_empty_i(fifo_empty),
.fifo_rd_o(fifo_rd),
.fifo_pixels_i(fifo_dout[g_pixel_width-1:0]),
.fifo_frame_i(fifo_dout[g_pixel_width]),
.fifo_got_frame_i(fifo_got_frame),
.p_req_o(p_req),
.p_islong_o(p_islong),
.p_type_o(p_type),
.p_wcount_o(p_wcount),
.p_command_o(p_command),
.p_payload_o(p_payload),
.p_dreq_i(p_dreq),
.p_last_o(p_last),
.host_a_i(host_a_i),
.host_d_i(host_d_i),
// .host_d_o(host_d_o),
.host_wr_i(host_wr_i)
);
////////////////
/// Pixel Buffer
////////////////
dsi_fifo #(
.g_width(g_pixel_width + 1),
.g_size(g_fifo_size)
) U_PixFifo (
.clk_i(clk_sys_i),
.rst_n_i(rst_n_i),
.d_i({fifo_frame_int, fifo_pixels_int}),
.we_i(fifo_wr_int),
.full_o(fifo_full_int),
.q_o(fifo_dout),
.rd_i(fifo_rd),
.empty_o(fifo_empty)
);
always@(posedge clk_sys_i)
if(!rst_n_i)
begin
fifo_rd_d0 <= 0;
fifo_got_frame <= 0;
end else begin
fifo_rd_d0 <= fifo_rd;
if(fifo_wr_int && fifo_frame_int)
fifo_got_frame <= 1;
else if (fifo_rd && fifo_dout[g_pixel_width])
fifo_got_frame <= 0;
end // else: !if(!rst_n_i)
////////////////
// Host regs
////////////////
reg [11:0] r_tick_div, tick_count;
always@(posedge clk_sys_i)
begin
if (!rst_n_i)
tick_count <= 0;
else begin
if(tick_count == r_tick_div)
begin
tick <= 1;
tick_count <= 0;
end else begin
tick <= 0;
tick_count <= tick_count + 1;
end
end // else: !if(!rst_n_i)
end // always@ (posedge clk_sys_i)
reg [31:0] host_d_self;
always@(posedge clk_sys_i)
if(!rst_n_i)
begin
r_tick_div <= 0;
r_dsi_clk_en <= 0;
lp_request <= 0;
host_d_self <= 0;
dsi_reset_n_o <= 0;
end else if(host_wr_i) begin
case(host_a_i)
`REG_TICK_DIV: r_tick_div <= host_d_i;
`REG_DSI_CTL: begin
r_dsi_clk_en <= host_d_i[0];
lp_request <= host_d_i[1];
end
`REG_LP_TX:
if(lp_ready) begin
lp_valid <= host_d_i[8];
lp_data <= host_d_i[7:0];
end
`REG_GPIO: begin
dsi_reset_n_o <= host_d_i[0];
end
endcase // case (host_a_i)
end else begin
lp_valid <= 0;
case(host_a_i)
`REG_DSI_CTL: begin
host_d_self[0] <= r_dsi_clk_en;
host_d_self[31:2] <= 0;
host_d_self[1] <= lp_ready;
end
default:
host_d_self <= 0;
endcase // case (host_a_i)
end // else: !if(host_wr_i)
assign host_d_o = host_d_self;
endmodule // dsi_core

View File

@ -0,0 +1,55 @@
/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* 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

128
hdl/rtl/dsi_core/dsi_fifo.v Normal file
View File

@ -0,0 +1,128 @@
/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* 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<g_size;i=i+1)
mem[i] = 0;
end
// synthesis translate_on
endmodule // dsi_fifo

View File

@ -0,0 +1,238 @@
/*
* DSI Core
* Copyright (C) 2013 twl <twlostow@printf.cc>
*
* 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_num_bytes;j=j+1)
assign q_o[8 * (g_num_bytes-1-j) + i] = d_i[8 * j + i];
endgenerate
endmodule
module dsi_byte_swapper
(
d_i,
size_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;
input [2:0] size_i;
wire [g_num_bytes * 8 - 1 : 0] swapped[1:g_num_bytes];
generate
genvar i, j, nbytes;
for(nbytes = 1; nbytes <= g_num_bytes; nbytes = nbytes + 1)
for(i=0;i<8;i=i+1)
begin
for(j=0;j<nbytes;j=j+1)
assign swapped[nbytes] [8 * (nbytes-1-j) + i] = d_i[8 * j + i];
for(j=nbytes;j<g_num_bytes;j=j+1)
assign swapped[nbytes] [j * 8 + i ] = 1'b0;
end
endgenerate
assign q_o = (size_i) <= g_num_bytes ? swapped[size_i] : 'hx;
endmodule
module dsi_byte_shifter
(
d_i,
shifted_o,
shift_i
);
parameter g_data_bytes = 3;
parameter g_max_shift = 3;
localparam c_output_width = 8 * (g_data_bytes + g_max_shift);
input [3:0] shift_i;
input [g_data_bytes * 8 - 1: 0] d_i;
output [c_output_width - 1: 0] shifted_o;
wire [c_output_width - 1 : 0] gen_array[0:g_max_shift];
genvar i;
generate
for (i=0;i<g_max_shift;i=i+1)
assign gen_array[i] = d_i << (i * 8);
endgenerate
assign shifted_o = gen_array[shift_i];
endmodule // dsi_byte_shifter
module dsi_packer
(
clk_i,
rst_n_i,
d_i,
d_size_i,
d_req_o,
d_valid_i,
d_empty_o,
q_o,
q_req_i,
q_flush_i,
q_valid_o
);
parameter g_input_bytes = 3;
parameter g_output_bytes = 3;
localparam c_shiftreg_bytes = 2 * (g_input_bytes > 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;