////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2011, Andrew "bunnie" Huang // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation and/or // other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////// // Notes // 1280 x 720p60 = 74.25 MHz pclk; 45 kHz horiz rate, 750 vertical // 1920 x 1080p24 = 74.25 MHz pclk; 27k Hz horiz rate, 1125 vertical ////////////////////////////////////////////////////////////////////////////// // removes I2C control elements when this is commented `define PRODUCTION // comment out for simulation, leave in for production // removes Rx device when this is commented, self-only mode is possible // also, uncomment the CLOCK_DEDICATED_ROUTE line inside the .ucf file // and also comment out the TIG paths as noted `define PASSTHROUGH 1 // enable SS clocking to the LCD interface to reduce noise (valid in both pass-thru and self-timed mode) `define SS_CLOCKING_TOP 1 // uncomment the below to enable pre version-8 timing detector behavior, i.e. detect timing // of the LCD stream during self-timed mode, instead of the Rx stream //`define TIMING_POSTX 1 `timescale 1 ns / 1 ps module hdmi_overlay ( input wire rstbtn_n, input wire clk26, //26 mhz oscillator input wire [3:0] RX0_TMDS, input wire [3:0] RX0_TMDSB, output wire [3:0] TX0_TMDS, output wire [3:0] TX0_TMDSB, input wire [7:2] LCD_R, input wire [7:2] LCD_G, input wire [7:2] LCD_B, output wire LCDO_DCLK, // changed to output... input wire LCD_DE, input wire LCD_HSYNC, input wire LCD_VSYNC, output wire VSYNC_STB, output reg LED0, output wire LED1, inout wire SDA, input wire SCL, inout wire DDC_SDA, output wire DDC_SDA_PU, output wire DDC_SDA_PD, input wire DDC_SCL, input wire HPD_N, output wire HPD_NOTIFY, output wire HPD_OVERRIDE, output wire SOURCE_NOTIFY, input wire CEC, // just a placeholder for CEC for now input wire CHUMBY_BEND, // to prevent this from being tied-off input wire LOWVOLT_N, output reg LOWVOLT_NOTIFY, // tell the CPU that we have a low voltage condition GPIO 93 output reg HDCP_AKSV // tell the CPU that AKSV was writ, so generate Km...GPIO 92 ); // wire LCD_DCLK_intbuf; wire box_active; wire box_active_raw; wire chroma_match; wire [7:0] blend_b; wire [7:0] blend_r; wire [7:0] blend_g; wire [7:0] chroma_r; wire [7:0] chroma_g; wire [7:0] chroma_b; wire [23:0] cipher_stream; wire clk26buf; // extend sync pulses and detect edge reg vsync_v; reg hsync_v; reg hsync_v2; reg vsync_v2; wire hsync_rising; wire vsync_rising; // autodetect sync polarity reg hdmi_vsync_pol; reg hdmi_hsync_pol; // compute HPD relay to host (delay one vsync) reg hpd_saw_vsync; // try to make it so that hdcp isn't used if it isn't ready wire hdcp_comp_ready; wire hdcp_is_ready; // timing derivation interface wire [11:0] t_hactive; // in pixels wire [11:0] t_vactive; // in lines wire [11:0] t_htotal; // in pixels wire [23:0] t_vtotal; // ** in PIXELS ** must divide by htotal in software wire [7:0] t_h_fp; // in pixels wire [7:0] t_h_bp; // in pixels wire [23:0] t_v_fp; // ** in PIXELS ** wire [23:0] t_v_bp; // ** in PIXELS ** wire [7:0] t_hsync_width; // in pixels wire [23:0] t_vsync_width; // ** in PIXELS ** wire [11:0] t_lcd_de_latency; // in lines wire [11:0] t_vsync_latency; // in lines wire [23:0] t_refclkcnt; // number of refclocks in a field // break self-mode toggle to a wire so we force it in the self-mode configuration reg self_mode; // note if HDCP was requested on a frame reg hdcp_requested; // de type selection wire de_sync; wire use_basic_de; // device DNA -- state machine at bottom reg [55:0] dna_data; // lock state of PLLs and channels wire ss_locked; wire tx0_plllckd; wire rx0_plllckd; wire rx0_psalgnerr; // channel phase alignment error wire rx0_blue_vld; wire rx0_green_vld; wire rx0_red_vld; wire rx0_blue_rdy; wire rx0_green_rdy; wire rx0_red_rdy; wire m720p_locked; ////////// I2C host interface //////// wire SDA_pd; wire [7:0] reg_addr; wire wr_stb; wire [7:0] reg_data_in; wire [7:0] reg_a2; wire SDA_int; wire [7:0] snoop_ctl; wire [7:0] snoop_rbk_adr; wire [7:0] snoop_rbk_dat; wire [7:0] hdcp_snoop_data; wire [7:0] hdcp_snoop_addr; wire [7:0] edid_snoop_data; wire [7:0] edid_snoop_addr; wire [7:0] comp_ctl; wire [15:0] window_w; wire [14:0] window_h; wire window_update; wire [15:0] window_x; wire [15:0] window_y; reg [11:0] window_x_buf; reg [11:0] window_y_buf; reg [11:0] window_w_buf; reg [11:0] window_h_buf; wire [7:0] ext1_ctl; wire [55:0] Km; wire [63:0] An; wire Aksv14_write; reg Km_rdy0; reg Km_rdy1; reg Km_rdy2; wire Km_ready; wire [7:0] edid_daddr; wire rst_skewmach; wire [3:0] line_full_level; wire [3:0] line_empty_level; wire [3:0] write_init_level; wire [3:0] read_init_level; wire [23:0] target_lead_pixels; wire reset_lock_machine; wire genlock_locked; wire [15:0] lock_tolerance; wire smartlock_on; wire modeline_write; wire [7:0] modeline_adr; wire [7:0] modeline_dat; wire rx_all_valid; assign rx_all_valid = (rx0_blue_vld & rx0_green_vld & rx0_red_vld); `ifdef PRODUCTION i2c_slave host_i2c( .SCL(SCL), .SDA(SDA_int), .SDA_pd(SDA_pd), .clk(clk26buf), .reset(~rstbtn_n), .i2c_device_addr(8'h3C), .reg_addr(reg_addr), .reg_data_in(reg_data_in), .wr_stb(wr_stb), .reg_0(snoop_ctl), .reg_1(snoop_rbk_adr), // reg_2 is nc internally .reg_3(comp_ctl), //`define REGWINDOWS `ifdef REGWINDOWS .reg_4(window_w[7:0]), .reg_5(window_w[15:8]), .reg_6(window_h[7:0]), .reg_7({window_update,window_h[14:8]}), .reg_8(window_x[7:0]), .reg_9(window_x[15:8]), .reg_a(window_y[7:0]), .reg_b(window_y[15:8]), `endif .reg_c(ext1_ctl), // hard coded now // .reg_d({line_full_level[3:0],line_empty_level[3:0]}), // .reg_e({write_init_level[3:0], read_init_level[3:0]}), // hard-wired to 240, 0, 240 // .reg_d(chroma_r), // .reg_e(chroma_g), // .reg_f(chroma_b), .reg_10({hdcp_requested,hdmi_vsync_pol,hdmi_hsync_pol,LOWVOLT_NOTIFY,1'b0,CEC, genlock_locked, CHUMBY_BEND}), .reg_11(lock_tolerance[7:0]), .reg_12(lock_tolerance[15:8]), .reg_13({modeline_write,modeline_adr[6:0]}), .reg_14(modeline_dat), .reg_15(target_lead_pixels[7:0]), .reg_16(target_lead_pixels[15:8]), .reg_17(target_lead_pixels[23:16]), // .reg_18(edid_daddr[7:0]), .reg_18({rx_all_valid, rx0_blue_rdy, rx0_green_rdy, rx0_red_rdy, rx0_psalgnerr, m720p_locked, tx0_plllckd, rx0_plllckd}), .reg_19(Km[7:0]), .reg_1a(Km[15:8]), .reg_1b(Km[23:16]), .reg_1c(Km[31:24]), .reg_1d(Km[39:32]), .reg_1e(Km[47:40]), .reg_1f(Km[55:48]), //// read-only registers after this point .reg_20(t_hactive[7:0]), .reg_21({4'b0,t_hactive[11:8]}), .reg_22(t_vactive[7:0]), .reg_23({4'b0,t_vactive[11:8]}), .reg_24(t_htotal[7:0]), .reg_25({4'b0,t_htotal[11:8]}), .reg_26(t_vtotal[7:0]), .reg_27(t_vtotal[15:8]), .reg_28(t_vtotal[23:16]), .reg_29(t_h_fp[7:0]), .reg_2a(t_h_bp[7:0]), .reg_2b(t_v_fp[7:0]), .reg_2c(t_v_fp[15:8]), .reg_2d(t_v_fp[23:16]), .reg_2e(t_v_bp[7:0]), .reg_2f(t_v_bp[15:8]), .reg_30(t_v_bp[23:16]), .reg_31(t_hsync_width[7:0]), .reg_32(t_vsync_width[7:0]), .reg_33(t_vsync_width[15:8]), .reg_34(t_vsync_width[23:16]), .reg_35(t_refclkcnt[7:0]), .reg_36(t_refclkcnt[15:8]), .reg_37(t_refclkcnt[23:16]), // .reg_38(t_lcd_de_latency[7:0]), // .reg_39({4'b0,t_lcd_de_latency[11:8]}), // .reg_3a(t_vsync_latency[7:0]), // .reg_3b({4'b0,t_vsync_latency[11:8]}), .reg_38(dna_data[7:0]), .reg_39(dna_data[15:8]), .reg_3a(dna_data[23:16]), .reg_3b(dna_data[31:24]), .reg_3c(dna_data[39:32]), .reg_3d(dna_data[47:40]), .reg_3e(dna_data[55:48]), .reg_3f(8'hD) // version number ); /////// version 4 changes // - added input registers to LCD path to clean up timing // - added a pipeline stage to the core video processing pipe // - adjusted the position of chroma decision versus chroma to remove right pink stripe // - fixed chroma to 240, 0, 240 to reduce computational complexity // - fixed timing files to get better coverage of the FPGA // - inverted clock to device DNA state machine to fix hold time race condition // - self-timed mode is now native, no need to switch FPGA configs // - added PLL and alignment/valid feedback registers to detect when source is present // - touch-up clock tree to improve clarity of timing definition & rule propagation // - full switch-over to PlanAhead tool for compilation /////// version 5 changes (log created 8/11/2011) // - changed blue LED from flashing to breathing /////// version 6 changes (log created 8/12/2011) // - added off state to LED which is automatically triggered when output not plugged in /////// version 7 changes (log created 8/12/2011) // - added SOURCE_NOTIFY reporting trigger // - removed HPD debounce circuit, so HPD reports even when no source is present /////// version 8 changes (log cerated 8/21/2011) // - changed timing detector to always report the timing of the Rx stream, even in self-timed mode /////// version 9 changes (log created 8/22/2011) // - removed setbox functionality. Box is always "full screen". // Registers 4-B are now deprecated (they are NOPs if written in this implementation, may // change to be active later). /////// version A changes (log created 8/22/2011) // - HDCP cipher now resets properly when Ksv is double-initialized // - EDID snooper for HDCP now limits read bounds to 5 to compensate // for tivo series 3 weirdness. /////// version B changes (log created 8/27/2011) // - timing closure only /////// version C changes (log created 8/27/2011) // - fix chroma issue in overlay mode, was checking too many bits, causing jagged edges on photos /////// version D changes (log created 9/5/2011) // assign SOURCE_NOTIFY = rx0_plllckd; // hard wire chroma because it never changes, optimize out some gates assign chroma_r = 8'd240; assign chroma_g = 8'd0; assign chroma_b = 8'd240; assign modeline_adr[7] = snoop_ctl[6]; // hack to add another bank into the modeline RAM // assign use_basic_de = ext1_ctl[0]; // these are hard-coded now, used to be registers assign line_full_level[3:0] = 4'h2; assign line_empty_level[3:0] = 4'h2; assign write_init_level[3:0] = 4'h1; assign read_init_level[3:0] = 4'h2; `else // !`ifdef PRODUCTION assign comp_ctl = 8'h09; // setup for testing stand-alone mode assign snoop_ctl = 8'h0; assign snoop_ctl = 8'h1; `endif // !`ifdef PRODUCTION // IBUF IBUF_sda (.I(SDA), .O(SDA_int)); IOBUF #(.DRIVE(12), .SLEW("SLOW")) IOBUF_sda (.IO(SDA), .I(1'b0), .T(!SDA_pd), .O(SDA_int)); //// I2C internal control wiring //// ///////////////// /// register 0: control snoop state (SNOOP_CTL r/w) // bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 // | MODEBNK | | | HPD_FRC | SQUASH | RD_STB | RD_HDCP // // bit 0 - RD_HDCP. When 1, select readback of the HDCP set; when 0, select EDID set // bit 1 - RD_STB. When high, update the contents of SNOOP_DAT with data at SNOOP_ADR // bit 2 - enable EDID squashing // bit 3 - when high, force HPD to show that nothing is plugged in; low, act as normal // bit 6 - sets the bank to write with register 0x13 (yah yah this is a hack) // ///////////////// /// register 1: snoop readback address (SNOOP_ADR r/w) // bits 7:0 are the address to read back from the snoop unit // ///////////////// /// register 2: snoop readback data (SNOOP_DAT ro) // bits 7:0 are the data corresponding to the last loaded snoop address as // selected by RD_HDCP bits in SNOOP_CTL when RD_STB was last toggled // // REVISION -- now dynamically relays the value specified by snoop_adr without having // to toggle RD_STB. RD_STB has no effect currently. ///////////////// // register 3: Compositing control (COMP_CTL r/w) // bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 // KM_SEM | RST_GNLK| SMRTLCK | RST_PLL | SELF | COMP_ON | KM_RDY | HDCP_ON // // bit 0 - enable HDCP encryption of the composited stream. Enables HDCP encryption // only if the HDCP cipher is used. If the input stream has no HDCP on it // then this bit has no meaning. // bit 1 - indicates that Km is ready and loaded (currently ignored) // bit 2 - enable compositing of incoming data from LCD port to HDMI stream // bit 3 - when set, ignore incoming data and generate sync based on LCD port signals // bit 4 - when set, resets PLLs only on the paths designated by bit3 ("self") // bit 5 - when set, enable "smart locking", i.e., genlock turns off once we're locked // bit 6 - reset the genlock control machine // bit 7 - Km semaphore -- used to indicate to the kernel whether an existing process // is controlling the Km derivation process. This is to resolve the issue where // the HPD will generate two events to cover Km generation in the case that // the final protocol requires a "restart" to get the correct Km value to stick // ///////////////// `ifdef REGWINDOWS ///////////// REGISTER 4 - B are now DEPRECATED. // register 4: window width // bits 7:0 are LSB of window width // ///////////////// // register 5: window width // bits 7:0 are MSB of window width // ///////////////// // register 6: window height // bits 7:0 are LSB of window height // ///////////////// // register 7: window height // bits 6:0 are MSB of window height // bit 7 is the "update" bit which informs the system to take the new values on the next // vsync period // ///////////////// // register 8: window X position // bits 7:0 are LSB of window X position // ///////////////// // register 9: window X position // bits 7:0 are MSB of window X position // ///////////////// // register A: window Y position // bits 7:0 are LSB of window Y position // ///////////////// // register B: window Y position // bits 7:0 are MSB of window Y position // /////////////////////////// END DEPRACATION BLOCK `endif ///////////////// // register C: extended control set (EXT1_CTL r/w) // bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 // | | | | | | CHROMA | // // bit 1: when set, turn on chroma keying; otherwise, always blend in // ///////////////// // NOTE: these are now hard-wired to 240, 0, 240. These registers will likely be deprecated soon. // register D: chroma R value, 8 bits // register E: chroma G value, 8 bits // register F: chroma B value, 8 bits // ///////////////// // register 0x10 is read-only: // bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 // HDCPDET| VSYNCPOL| HSYNCPOL| LOWVOLT | | CEC | LOCKED | BEND // bit 0: chumby_bend pin state (tied off to insure configuratios as an input) // bit 1: indicates that the genlock machine has locked LCD to HDMI streams // bit 2: CEC pin state (tied off to insure configuratios as an input) // bit 4: when high indicates that a low voltage condition was detected; only active during condition // there is also an interrupt to the CPU that fires // bit 5: indicates the polarity of the HSYNC detected on the HDMI stream, 1 = active high // bit 6: indicates the polarity of the VSYNC detected on the HDMI stream, 1 = active high // bit 7: when high, indicates that an HDCP stream is being encrypted. Not active during // horiz and vert sync periods. // ///////////////// // register 0x11-12: // lock tolerance, in pixels, in little-endian byte order // This defines the tolerance of the "lock" threshold. This value matters mostly when // "smart locking" is turned on, i.e., when we want to disable genlock once we're within // our locking tolerance window. // ///////////////// // register 0x13 is address of modeline RAM to write // 7 is a write strobe (write when high) // 6:0 is the actual modeline address // ///////////////// // register 0x14 is the data to write into the modeline RAM // 7:0 is the data // ///////////////// // registers 0x15-0x17: // lock target count, in pixels, in little-endian byte order. // Lock target count is the amount of time that the LCD interface should lead the // HDMI inteface for producing data. The amount of time should be large enough to // absorb timing variations in the interrupt latency handling of the PXA168, but // in all cases smaller than 8 lines of video (that's the size of the line buffers). // // The total time should be expressed in units of pixels, not lines. // ///////////////// // register 0x18 is read-only: // bit 7 | bit 6 | bit 5 | bit 4 | bit 3 | bit 2 | bit 1 | bit 0 // RX_VLD | B_RDY | G_RDY | R_RDY | ALGNERR | SYNLCK | TXLCK | RXLCK // bit 0: rx PLL is locked, indicates that a clock is present and cable is plugged in // bit 1: tx PLL is locked. This should generally always be the case. // bit 2: synthesizer DCM is locked. This should generally always be the case. // bit 3: rx alignment error // bit 4: red channel has received a valid pixel // bit 5: green chanel has received a valid pixel // bit 6: blue channel has received a valid pixel // bit 7: all RX chanels are phase aligned and producing valid data // ///////////////// // registers 0x19-0x1f: Km // 56-bit value of Km, entered in little-endian order. // ///////////////// // All registers after this point are read-only, and byte-order is little-endian ///////////////// // register 0x20-21: horizontal active in pixels // register 0x22-23: vertical active in lines // register 0x24-25: horizontal total width in pixels // register 0x26-28: vertical total height in pixels (not lines) // register 0x29: horizontal front porch in pixels // register 0x2a: horizontal back porch in pixels // register 0x2b-2d: vertical front porch in pixels (not lines) // register 0x2e-30: vertical back porch in pixels (not lines) // register 0x31: horizontal sync width in pixels // register 0x32-0x34: vertical sync width in pixels (not lines) // register 0x35-0x37: reference clock count cycles // // register 0x38-0x3e: device ID (7 bytes) // // register 0x3f: version number //////////// DEPRACATED REGISTERS ////////////// (but not confident they are dead yet) // register D: line empty/full levels // This sets the level at which we declare the line buffers to be "empty" or "full" // This is on a the granularity of a full video line, not at the pixel level. The // pixel-level full/empty is hard-coded by the FIFO primitive. // bit 7 is ignored // bits [6:4] are the full level target: nominally 2 // bit 3 is ignored // bits [2:0] are the empty level target: nominally 2 // ///////////////// // register E: write and read initial levels // This sets the initial state of the write/read pointers, reset on every vsync. // Note that the actual bit vector that keeps track of active lines can be much longer // than 4 bits, but we only get to diddle with the bottom four bits in this implementation. // bits [7:4] are for the write: nominally 1 // bits [3:0] are for the read: nominally 2 // ///////////////// // register F: reserved // `ifdef PRODUCTION `define EDID_SNOOP 1 // turn on EDID snooping assign reg_addr = 8'h02; assign wr_stb = snoop_ctl[1]; `ifdef EDID_SNOOP assign reg_data_in[7:0] = snoop_ctl[0] ? hdcp_snoop_data[7:0] : edid_snoop_data[7:0]; assign edid_snoop_addr = snoop_rbk_adr; `else assign reg_data_in[7:0] = hdcp_snoop_data[7:0]; `endif assign hdcp_snoop_addr = snoop_rbk_adr; /////// DDC snooping interface ////// wire DDC_SDA_int; wire DDC_SDA_pu_int; wire DDC_SDA_pd_int; i2c_snoop ddc_hdcp_snoop ( .SCL(!DDC_SCL), // inverters on inputs... .SDA(!DDC_SDA_int), .clk(clk26buf), .reset(~rstbtn_n), .i2c_snoop_addr(8'h74), // HDCP address *only* is snooped by this one .reg_addr(hdcp_snoop_addr), .reg_dout(hdcp_snoop_data), .An(An), .Aksv14_write(Aksv14_write) ); `ifdef EDID_SNOOP /////// EDID snooping interface ////// i2c_snoop_edid ddc_edid_snoop ( .SCL(!DDC_SCL), .SDA(!DDC_SDA_int), .clk(clk26buf), .reset(~rstbtn_n), .i2c_snoop_addr(8'h74), // all *but* this address is snooped by this one .reg_addr(edid_snoop_addr), .reg_dout(edid_snoop_data) ); i2c_squash_edid ddc_edid_squash ( .SCL(!DDC_SCL), .SDA(!DDC_SDA_int), .clk(clk26buf), .reset(~rstbtn_n), .SDA_pu(DDC_SDA_pu_int), .SDA_pd(DDC_SDA_pd_int), .i2c_snoop_addr(8'ha0), // only reads from this addres can be squashed .modeline_write(modeline_write), .modeline_dat(modeline_dat), .modeline_adr(modeline_adr) ); // IOBUF #(.DRIVE(24), .SLEW("SLOW")) IOBUF_DDC_sda (.IO(DDC_SDA), .I(DDC_SDA_pu), // .T(!(DDC_SDA_pd | DDC_SDA_pu) | !snoop_ctl[2]), // .O(DDC_SDA_int)); // and with inverse of SDA_PD to ensure we never get overlap of pullup/pulldown and thus DISASTER assign DDC_SDA_PU = (DDC_SDA_pu_int & snoop_ctl[2]) & !DDC_SDA_pd_int; assign DDC_SDA_PD = DDC_SDA_pd_int & snoop_ctl[2]; IBUF IBUF_DDC_sda (.I(DDC_SDA), .O(DDC_SDA_int)); `endif `endif //////////////////////////////////////////////////// // utility clock buffer //////////////////////////////////////////////////// // BUFIO2 #(.DIVIDE_BYPASS("FALSE"), .DIVIDE(5)) // sysclk_div (.DIVCLK(clk26m), .IOCLK(), .SERDESSTROBE(), .I(clk26)); wire clk26_ibuf; IBUFG clk26buf_ibuf(.I(clk26), .O(clk26ibuf)); BUFG clk26buf_buf (.I(clk26ibuf), .O(clk26buf)); // BUFG clk26buf_bufx(.I(clk26ibuf), .O(clk26bufpll)); wire tx0_pclk; // tx clock got promoted above input port because // input port is compiled out in some cases ///////////////////////// // // Input Port 0 // ///////////////////////// wire rx0_pclk, rx0_pclkx2, rx0_pclkx10, rx0_pllclk0; wire rx0_reset; wire rx0_serdesstrobe; wire rx0_hsync; // hsync data wire rx0_vsync; // vsync data wire rx0_de; // data enable wire rx0_basic_de; wire [7:0] rx0_red; // pixel data out wire [7:0] rx0_green; // pixel data out wire [7:0] rx0_blue; // pixel data out wire [29:0] rx0_sdata; wire rx0_cv; wire rx0_encoding; wire rx0_hdcp_ena; wire [3:0] rx0_red_di; wire [3:0] rx0_blue_di; wire [3:0] rx0_green_di; wire rx0_data_gb; wire rx0_video_gb; wire [3:0] rx0_ctl_code; wire rx0_line_end; `ifdef PASSTHROUGH dvi_decoder dvi_rx0 ( //These are input ports .tmdsclk_p (RX0_TMDS[3]), .tmdsclk_n (RX0_TMDSB[3]), .blue_p (RX0_TMDS[0]), .green_p (RX0_TMDS[1]), .red_p (RX0_TMDS[2]), .blue_n (RX0_TMDSB[0]), .green_n (RX0_TMDSB[1]), .red_n (RX0_TMDSB[2]), .exrst (~rstbtn_n || HPD_N), .pllreset ((comp_ctl[4] && !self_mode)), //These are output ports .reset (rx0_reset), .pclk (rx0_pclk), .pclkx2 (rx0_pclkx2), .pclkx10 (rx0_pclkx10), .pllclk0 (rx0_pllclk0), // PLL x10 output .pllclk1 (rx0_pllclk1), // PLL x1 output .pllclk2 (rx0_pllclk2), // PLL x2 output .pll_lckd (rx0_plllckd), .tmdsclk (rx0_tmdsclk), .serdesstrobe(rx0_serdesstrobe), .hsync (rx0_hsync), .vsync (rx0_vsync), .de (rx0_de), .basic_de (rx0_basic_de), .blue_vld (rx0_blue_vld), .green_vld (rx0_green_vld), .red_vld (rx0_red_vld), .blue_rdy (rx0_blue_rdy), .green_rdy (rx0_green_rdy), .red_rdy (rx0_red_rdy), .psalgnerr (rx0_psalgnerr), .sdout (rx0_sdata), .red (rx0_red), .green (rx0_green), .blue (rx0_blue), .encoding (rx0_encoding), .hdcp_ena (rx0_hdcp_ena), .red_di (rx0_red_di), .green_di (rx0_green_di), .blue_di (rx0_blue_di), .data_gb (rx0_data_gb), .video_gb (rx0_video_gb), .ctl_code (rx0_ctl_code), .cv (rx0_cv), .line_end (rx0_line_end) ); // // This BUFG mirrors the rx0 clock // This way we have a matched skew between the RX pclk clocks and the TX pclk // // BUFG tx0_bufg_pclk (.I(self_mode ? tx0_pclk_self : rx0_pllclk1), .O(tx0_pclk)); // clock comes from rx is passthru mode wire tx0_pclk_ss; wire tx0_pclk_ss_unbuf; // assign self_mode = comp_ctl[3]; reg self_mode_pre; always @(posedge tx0_pclk_self) begin self_mode_pre <= comp_ctl[3]; self_mode <= self_mode_pre; end wire tx0_pclk_todcm; BUFGMUX tx0_bufg_mux (.I0(rx0_pllclk1), .I1(tx0_pclk_self), .S(self_mode_pre), .O(tx0_pclk)); BUFGMUX tx0_bufg_muxdcm (.I0(rx0_pllclk1), .I1(tx0_pclk_self), .S(self_mode_pre), .O(tx0_pclk_todcm)); // clkgendcm_720p60hz selfclockgen (.CLK_IN1(clk26buf), .CLK_OUT1(tx0_pclk_ss), .RESET((comp_ctl[4] && self_mode)), .LOCKED(m720p_locked) ); clkgendcm_720p60hz selfclockgen (.CLK_IN1(clk26buf), .CLK_OUT1(tx0_pclk_self), .RESET((comp_ctl[4] && self_mode)), .LOCKED(m720p_locked) ); /* // use spread spectrum clocking to reduce emissions... DCM_CLKGEN #( .DFS_OSCILLATOR_MODE("PHASE_FREQ_LOCK"), .CLKIN_PERIOD ("13.48"), .SPREAD_SPECTRUM ("CENTER_LOW_SPREAD"), // .CLKFX_MD_MAX("1.0"), .CLKFX_MULTIPLY (4), .CLKFX_DIVIDE (4) ) dcm_fcc_spreads_me_wide ( .CLKIN (tx0_pclk_ss), .FREEZEDCM (1'b0), .PROGDATA (1'b0), .PROGEN (1'b0), .PROGCLK (1'b0), // .PROGDONE (1'b0), // .CLKFX180 (CLKFX180_DCM), // .CLKFXDV (CLKFXDV_DCM), // .LOCKED (clkgen_locked), .RST (self_mode || comp_ctl[4]), .CLKFX (tx0_pclk_ss_unbuf), .LOCKED(ss_locked) ); BUFG tmdsclk_bfgss (.I(tx0_pclk_ss_unbuf), .O(tx0_pclk_self) ); */ `else // !`ifdef PASSTHROUGH assign self_mode = 1'b1; // generate internal 720p clock for self-timed mode operation wire m720p_clk; `ifdef SS_CLOCKING_TOP wire m720p_locked; // not currently used wire progdata_int; wire progen_int; wire progdone; wire clkgen_locked; wire tx0_pclk_unbuf; wire tx0_pclk_ss; wire tx0_pclk_ss_unbuf; clk_720p_60hz clk720p (.CLK_IN1(clk26bufpll), .CLK_OUT1(tx0_pclk_ss), .RESET((comp_ctl[4] && self_mode)), .LOCKED(m720p_locked) ); // use spread spectrum clocking to reduce emissions... DCM_CLKGEN #( .DFS_OSCILLATOR_MODE("PHASE_FREQ_LOCK"), .CLKIN_PERIOD ("13.48"), .SPREAD_SPECTRUM ("CENTER_HIGH_SPREAD"), // .CLKFX_MD_MAX("1.0"), .CLKFX_MULTIPLY (4), .CLKFX_DIVIDE (4) ) dcm_fcc_spreads_me_wide ( .CLKIN (tx0_pclk_ss), .FREEZEDCM (1'b0), .PROGDATA (1'b0), .PROGEN (1'b0), .PROGCLK (1'b0), // .PROGDONE (1'b0), // .CLKFX180 (CLKFX180_DCM), // .CLKFXDV (CLKFXDV_DCM), // .LOCKED (clkgen_locked), .RST (comp_ctl[4]), .CLKFX (tx0_pclk_ss_unbuf), .LOCKED(ss_locked) ); BUFG tmdsclk_bfgss (.I(tx0_pclk_ss_unbuf), .O(tx0_pclk) ); // `else // !`ifdef SS_CLOCKING_TOP assign ss_locked = 1'b1; clk_720p_60hz clk720p (.CLK_IN1(clk26bufpll), .CLK_OUT1(tx0_pclk), .RESET((comp_ctl[4] && self_mode)), .LOCKED(m720p_locked) ); // BUFG tx0_bufg_pclk (.I(self_mode ? LCD_DCLK_intbuf : rx0_pllclk1), .O(tx0_pclk)); // BUFG tx0_bufg_pclk (.I(m720p_clk), .O(tx0_pclk)); // clock comes from freqsynth if internal `endif // !`ifdef SS_CLOCKING_TOP ///// dummy tie-offs so we don't need a separate .UCF for the self-timed case wire [3:0] dummy_tmds; IBUFDS #(.IOSTANDARD("TMDS_33"), .DIFF_TERM("FALSE") ) ibuf_dummy0 (.I(RX0_TMDS[0]), .IB(RX0_TMDSB[0]), .O(dummy_tmds[0])); IBUFDS #(.IOSTANDARD("TMDS_33"), .DIFF_TERM("FALSE") ) ibuf_dummy1 (.I(RX0_TMDS[1]), .IB(RX0_TMDSB[1]), .O(dummy_tmds[1])); IBUFDS #(.IOSTANDARD("TMDS_33"), .DIFF_TERM("FALSE") ) ibuf_dummy2 (.I(RX0_TMDS[2]), .IB(RX0_TMDSB[2]), .O(dummy_tmds[2])); IBUFDS #(.IOSTANDARD("TMDS_33"), .DIFF_TERM("FALSE") ) ibuf_dummy3 (.I(RX0_TMDS[3]), .IB(RX0_TMDSB[3]), .O(dummy_tmds[3])); `endif // !`ifdef PASSTHROUGH // a simple pipeline register for LCD input retiming reg lcdr_de; reg lcdr_hsync; reg lcdr_vsync; reg [5:0] lcdr_b; reg [5:0] lcdr_g; reg [5:0] lcdr_r; always @(posedge tx0_pclk) begin lcdr_de <= LCD_DE; lcdr_hsync <= LCD_HSYNC; lcdr_vsync <= LCD_VSYNC; lcdr_b <= LCD_B[7:2]; lcdr_g <= LCD_G[7:2]; lcdr_r <= LCD_R[7:2]; end // this should be safe to have outside the ifdef zone wire chroma_match_self; assign chroma_match_self = (({lcdr_b[5:0],lcdr_b[0],lcdr_b[0]} == chroma_b[7:0]) && ( {lcdr_r[5:0],lcdr_r[0],lcdr_r[0]} == chroma_r[7:0]) && ( {lcdr_g[5:0],lcdr_g[0],lcdr_g[0]} == chroma_g[7:0])) && ext1_ctl[1]; ///////////////// // // Output Port 0 // ///////////////// reg tx0_de; reg tx0_basic_de; wire tx0_pclkx2; wire tx0_pclkx10; wire tx0_serdesstrobe; wire tx0_reset; reg [7:0] tx0_blue; reg [7:0] tx0_green; reg [7:0] tx0_red; reg tx0_hsync; reg tx0_vsync; wire tx0_pll_reset; reg tx0_vid_pa; reg tx0_vid_gb; reg tx0_dat_pa; reg tx0_dat_gb; reg tx0_dat_ena; reg [3:0] tx0_ctl_code; reg [9:0] tx0_dat_din; reg [29:0] tx0_sdata; reg tx0_cv; reg tx1_de; reg tx1_basic_de; reg [7:0] tx1_blue; reg [7:0] tx1_green; reg [7:0] tx1_red; reg tx1_hsync; reg tx1_vsync; reg tx1_vid_pa; reg tx1_vid_gb; reg tx1_dat_pa; reg tx1_dat_gb; reg tx1_dat_ena; reg [3:0] tx1_ctl_code; reg [9:0] tx1_dat_din; reg [29:0] tx1_sdata; reg tx1_cv; reg tx2_de; reg tx2_basic_de; reg [7:0] tx2_blue; reg [7:0] tx2_green; reg [7:0] tx2_red; reg tx2_hsync; reg tx2_vsync; reg tx2_vid_pa; reg tx2_vid_gb; reg tx2_dat_pa; reg tx2_dat_gb; reg tx2_dat_ena; reg [3:0] tx2_ctl_code; reg [9:0] tx2_dat_din; reg [29:0] tx2_sdata; reg tx2_cv; wire computed_gb; wire computed_ctl_code; always @ (posedge tx0_pclk or posedge tx0_reset) begin if( tx0_reset == 1'b1 ) begin tx0_de <= 1'b0; tx0_blue <= 8'b0; tx0_green <= 8'b0; tx0_red <= 8'b0; tx0_hsync <= 1'b0; tx0_vsync <= 1'b0; tx0_vid_pa <= 1'b0; tx0_vid_gb <= 1'b0; tx0_dat_pa <= 1'b0; tx0_dat_gb <= 1'b0; tx0_dat_ena <= 1'b0; tx0_ctl_code <= 4'b0; tx0_dat_din <= 10'b0; tx0_sdata <= 30'b0; tx0_cv <= 1'b0; tx1_de <= 1'b0; tx1_blue <= 8'b0; tx1_green <= 8'b0; tx1_red <= 8'b0; tx1_hsync <= 1'b0; tx1_vsync <= 1'b0; tx1_vid_pa <= 1'b0; tx1_vid_gb <= 1'b0; tx1_dat_pa <= 1'b0; tx1_dat_gb <= 1'b0; tx1_dat_ena <= 1'b0; tx1_ctl_code <= 4'b0; tx1_dat_din <= 10'b0; tx1_sdata <= 30'b0; tx1_cv <= 1'b0; tx2_de <= 1'b0; tx2_hsync <= 1'b0; tx2_vsync <= 1'b0; tx2_vid_pa <= 1'b0; tx2_vid_gb <= 1'b0; tx2_dat_pa <= 1'b0; tx2_dat_gb <= 1'b0; tx2_dat_ena <= 1'b0; tx2_ctl_code <= 4'b0; tx2_dat_din <= 10'b0; tx2_sdata <= 30'b0; tx2_cv <= 1'b0; end else begin // if ( reset == 1'b1 ) ///////// earlier pipe stage tx0_de <= rx0_de; tx0_basic_de <= rx0_basic_de; tx0_blue <= rx0_blue; tx0_green <= rx0_green; tx0_red <= rx0_red; tx0_hsync <= rx0_hsync; tx0_vsync <= rx0_vsync; tx0_vid_gb <= rx0_video_gb; tx0_vid_pa <= (rx0_ctl_code[3:0] == 4'b0001); tx0_dat_gb <= rx0_data_gb; tx0_dat_pa <= (rx0_ctl_code[3:0] == 4'b0101); tx0_dat_ena <= rx0_encoding; tx0_ctl_code <= rx0_ctl_code; tx0_dat_din[9:0] <= {rx0_blue_di[1:0],rx0_red_di[3:0],rx0_green_di[3:0]}; tx0_sdata <= rx0_sdata; tx0_cv <= rx0_cv; ///////// later pipe stage if( self_mode ) begin // self-timed tx1_de <= lcdr_de; // de is always active high tx1_blue <= chroma_match_self ? 8'b0 : {lcdr_b[5:0],lcdr_b[0],lcdr_b[0]}; tx1_green <= chroma_match_self ? 8'b0 : {lcdr_g[5:0],lcdr_g[0],lcdr_g[0]}; tx1_red <= chroma_match_self ? 8'b0 : {lcdr_r[5:0],lcdr_r[0],lcdr_r[0]}; tx1_hsync <= lcdr_hsync; // sync signals from CPU are always active high tx1_vsync <= lcdr_vsync; // tx1_vid_gb <= computed_gb; tx1_vid_gb <= 0; tx1_vid_pa <= 0; // this is a deprecated interface tx1_dat_gb <= 0; tx1_dat_pa <= 0; tx1_dat_ena <= 0; tx1_dat_din[9:0] <= 0; tx1_sdata <= 0; tx1_cv <= 1'b0; // not used // tx1_ctl_code <= computed_ctl_code; // this is the real pa (encoded as ctl code) tx1_ctl_code <= 4'b0; end else begin // passing through tx1_de <= tx0_de; tx1_basic_de <= tx0_basic_de; tx1_blue <= tx0_blue; tx1_green <= tx0_green; tx1_red <= tx0_red; tx1_hsync <= tx0_hsync; tx1_vsync <= tx0_vsync; tx1_vid_gb <= tx0_vid_gb; tx1_vid_pa <= tx0_vid_pa; tx1_dat_gb <= tx0_dat_gb; tx1_dat_pa <= tx0_dat_pa; tx1_dat_ena <= tx0_dat_ena; tx1_ctl_code <= tx0_ctl_code; tx1_dat_din[9:0] <= tx0_dat_din[9:0]; tx1_sdata <= tx0_sdata; tx1_cv <= tx0_cv; end // else: !if( self_mode ) tx2_de <= tx1_de; tx2_hsync <= tx1_hsync; tx2_vsync <= tx1_vsync; tx2_vid_pa <= tx1_vid_pa; tx2_vid_gb <= tx1_vid_gb; tx2_dat_pa <= tx1_dat_pa; tx2_dat_gb <= tx1_dat_gb; tx2_dat_ena <= tx1_dat_ena; tx2_ctl_code <= tx1_ctl_code; tx2_dat_din <= tx1_dat_din; tx2_sdata <= tx1_sdata; tx2_cv <= tx1_cv; end // else: !if( reset == 1'b1 ) end // always @ (posedge pclk or posedge reset) // assign de_sync = use_basic_de ? tx0_basic_de : tx0_de; assign de_sync = tx0_de; // assuming this doesn't need to be pipelined... assign tx0_pll_reset = (rx0_reset && !self_mode) || (comp_ctl[4] && self_mode); // reg tx0_reset_wire; // always @(posedge tx0_pclk) begin // tx0_reset_wire <= rx0_reset || (comp_ctl[4] && self_mode); // end // BUFG tx0_reset_bufg( .I(tx0_reset_wire), .O(tx0_rstin)); assign tx0_rstin = (rx0_reset && !self_mode) || (comp_ctl[4] && self_mode); gbgen gbgen ( .pclk(tx0_pclk), .rstin(tx0_rstin), .vsync(lcdr_vsync), .hsync(lcdr_hsync), .sync_pol(1'b1), // sync from CPU is always active high .de(lcdr_de), .gb(computed_gb), .code(computed_ctl_code) ); ////////////////////////////////////////////////////////////////// // Instantiate a dedicate PLL for output port ////////////////////////////////////////////////////////////////// wire tx0_clkfbout, tx0_clkfbin; wire tx0_pllclk0, tx0_pllclk2; PLL_BASE # ( // .CLKIN_PERIOD(10.526315), // 95 MHz // .CLKIN_PERIOD(35.34), // 28.29 MHz 480p/60 .CLKIN_PERIOD(13.481449525), // 74.176 MHz .CLKFBOUT_MULT(10), //set VCO to 10x of CLKIN .CLKOUT0_DIVIDE(1), .CLKOUT1_DIVIDE(10), .CLKOUT2_DIVIDE(5), // .BANDWIDTH("LOW"), // normally not here .COMPENSATION("SOURCE_SYNCHRONOUS") ) PLL_OSERDES_0 ( .CLKFBOUT(tx0_clkfbout), .CLKOUT0(tx0_pllclk0), .CLKOUT1(), .CLKOUT2(tx0_pllclk2), .CLKOUT3(), .CLKOUT4(), .CLKOUT5(), .LOCKED(tx0_plllckd), .CLKFBIN(tx0_clkfbin), .CLKIN(tx0_pclk_todcm), .RST(tx0_pll_reset || comp_ctl[4] || (!m720p_locked & self_mode)) ); wire lcd_intbuf; //////////////////// buffer our Rx clock back to the CPU so we are meso-synchronous ODDR2 lcd_refclk_buf (.D0(1'b1), .D1(1'b0), .C0(tx0_pclk), .C1(!tx0_pclk), .Q(LCDO_DCLK), .CE(1), .R(0), .S(0) ); // wire LCD_fbkclk; // IBUF lcd_fbk_ibuf(.I(LCDO_DCLK), .O(LCD_fbkclk)); // BUFG lcd_fbk_buf(.I(LCD_fbkclk), .O(lcd_intbuf)); // // This BUFG is needed in order to deskew between PLL clkin and clkout // So the tx0 pclkx2 and pclkx10 will have the same phase as the pclk input // BUFG tx0_clkfb_buf (.I(tx0_clkfbout), .O(tx0_clkfbin)); // // regenerate pclkx2 for TX // BUFG tx0_pclkx2_buf (.I(tx0_pllclk2), .O(tx0_pclkx2)); // // regenerate pclkx10 for TX // wire tx0_bufpll_lock; BUFPLL #(.DIVIDE(5)) tx0_ioclk_buf (.PLLIN(tx0_pllclk0), .GCLK(tx0_pclkx2), .LOCKED(tx0_plllckd), .IOCLK(tx0_pclkx10), .SERDESSTROBE(tx0_serdesstrobe), .LOCK(tx0_bufpll_lock)); // reset off of master PLL lock, not BUFPLL lock assign tx0_reset = (~tx0_plllckd) || (comp_ctl[4] & self_mode); wire byp_error; reg [7:0] blend_b1; reg [7:0] blend_g1; reg [7:0] blend_r1; assign hdcp_comp_ready = comp_ctl[0] && hdcp_is_ready; always @ (posedge tx0_pclk or posedge tx0_reset) begin if( tx0_reset ) begin tx2_blue <= 0; tx2_green <= 0; tx2_red <= 0; blend_b1 <= 0; blend_r1 <= 0; blend_g1 <= 0; end else begin blend_b1 <= blend_b; blend_r1 <= blend_r; blend_g1 <= blend_g; tx2_blue <= !(box_active & comp_ctl[2]) ? tx1_blue : hdcp_comp_ready ? blend_b1[7:0] ^ cipher_stream[7:0] : blend_b1[7:0]; tx2_green <= !(box_active & comp_ctl[2]) ? tx1_green : hdcp_comp_ready ? blend_g1[7:0] ^ cipher_stream[15:8] : blend_g1[7:0]; tx2_red <= !(box_active & comp_ctl[2]) ? tx1_red : hdcp_comp_ready ? blend_r1[7:0] ^ cipher_stream[23:16] : blend_r1[7:0]; end // else: !if( tx0_reset ) end // always @ (posedge tx0_pclk or posedge tx0_reset) dvi_encoder_top dvi_tx0 ( .pclk (tx0_pclk), .pclkx2 (tx0_pclkx2), .pclkx10 (tx0_pclkx10), .serdesstrobe(tx0_serdesstrobe), .rstin (tx0_reset), .blue_din (tx2_blue), .green_din (tx2_green), .red_din (tx2_red), .hsync (tx2_hsync), .vsync (tx2_vsync), .de (tx2_de), .TMDS (TX0_TMDS), .TMDSB (TX0_TMDSB), .vid_pa (tx2_vid_pa), .vid_gb (tx2_vid_gb), .dat_pa (tx2_dat_pa), .dat_gb (tx2_dat_gb), .dat_ena (tx2_dat_ena), .dat_din (tx2_dat_din), .ctl_code (tx2_ctl_code), .bypass_sdata(tx2_sdata), .bypass_ena (1'b1), .byp_error (byp_error), .box_active ((box_active && comp_ctl[2]) || self_mode) ); assign hsync_rising = hsync_v & !hsync_v2; assign vsync_rising = vsync_v & !vsync_v2; // extend hsync's validity when control periods are inactive always @(posedge tx0_pclk or posedge tx0_reset) begin if( tx0_reset == 1'b1 ) begin vsync_v <= 0; hsync_v <= 0; vsync_v2 <= 0; hsync_v2 <= 0; end else begin vsync_v2 <= vsync_v; hsync_v2 <= hsync_v; if(tx0_cv) begin vsync_v <= tx0_vsync ^ !hdmi_vsync_pol; hsync_v <= tx0_hsync ^ !hdmi_hsync_pol; end else begin vsync_v <= vsync_v; hsync_v <= hsync_v; end end // else: !if( tx0_reset == 1'b1 ) end // always @ (posedge tx0_pclk or posedge tx0_reset) `ifdef REGWINDOWS always @(posedge tx0_pclk or posedge tx0_rstin) begin if(tx0_rstin) begin window_x_buf <= 12'b0; window_y_buf <= 12'b0; window_h_buf <= 12'b0; window_w_buf <= 12'b0; end else begin if( vsync_rising && window_update ) begin window_x_buf[11:0] <= window_x[11:0]; window_y_buf[11:0] <= window_y[11:0]; window_w_buf[11:0] <= window_w[11:0]; window_h_buf[11:0] <= window_h[11:0]; end else begin window_x_buf[11:0] <= window_x_buf[11:0]; window_y_buf[11:0] <= window_y_buf[11:0]; window_w_buf[11:0] <= window_w_buf[11:0]; window_h_buf[11:0] <= window_h_buf[11:0]; end // else: !if( vsync_rising && window_update ) end // else: !if(tx0_rstin) end // always @ (posedge tx0_pclk or posedge tx0_rstin) // instantiate the timing module that generates the mask box for enabling the overlay boxtiming boxtimer ( .pclk(tx0_pclk), .rstin(tx0_rstin), // .vsync(tx0_vsync ^ !hdmi_vsync_pol), // .hsync(tx0_hsync ^ !hdmi_hsync_pol), .vsync(vsync_v), .hsync(hsync_v), .sync_pol(1'b1), // with auto-detect, polarity is always "righted" .de(de_sync), .cv(tx0_cv), .hpos(window_x_buf[11:0]), .hsize(window_w_buf[11:0]), .vpos(window_y_buf[11:0]), .vsize(window_h_buf[11:0]), .box_active(box_active_raw) ); `else // !`ifdef REGWINDOWS assign box_active_raw = de_sync & !(vsync_v || hsync_v); `endif // !`ifdef REGWINDOWS // chroma should only check high 6 bits because the lower bits don't exist assign chroma_match = (blend_b[7:2] == chroma_b[7:2]) && (blend_r[7:2] == chroma_r[7:2]) && (blend_g[7:2] == chroma_g[7:2]); assign box_active = box_active_raw && (!chroma_match || !ext1_ctl[1]); // hpd debounce and delay always @(posedge tx0_pclk or posedge tx0_reset) begin if( tx0_reset == 1'b1 ) begin hpd_saw_vsync <= 1'b0; end else begin if( HPD_N ) begin hpd_saw_vsync <= 1'b0; end else begin if( self_mode ) begin // in self-timed mode, there's no external vsync to sync to, so just pass this through hpd_saw_vsync <= 1'b1; end else begin // in genlock mode, synch to a vsync edge as a debounce mechanism if( vsync_rising ) begin hpd_saw_vsync <= 1'b1; end else begin hpd_saw_vsync <= hpd_saw_vsync; end end end end end // always @ (posedge tx0_pclk or posedge tx0_reset) // assign HPD_NOTIFY = hpd_saw_vsync; assign HPD_NOTIFY = !HPD_N; // fuck debouncing, the CPU can take care of it. 800 MHz of CPU power and all it has to do is... assign HPD_OVERRIDE = snoop_ctl[3]; // force hpd to look like nothing is plugged in hen asserted /////////// timing extraction machine `ifdef TIMING_POSTX // run the timing detector after the Tx mux, so that during self-timed mode we get // the timing of what we're putting to the screen as feedback... timing_detector timing_det ( .pclk(tx0_pclk), .rstin(tx0_rstin), .vsync(self_mode ? tx1_vsync : vsync_v), // vsync_v is polarity-corrrected .hsync(self_mode ? tx1_vsync : hsync_v), // hsync_v is polarity-corrected .de(self_mode ? tx1_de : de_sync), .refclk(clk26buf), // actually 26 MHz due to PXA168 multipliers .lcd_de(lcdr_de), .lcd_vsync(lcdr_vsync), .hactive(t_hactive), // pixels .vactive(t_vactive), // pixels .htotal(t_htotal), // pixels .vtotal(t_vtotal), // PIXELS .h_frontporch(t_h_fp), // pixels .h_backporch(t_h_bp), // pixels .v_frontporch(t_v_fp), // PIXELS .v_backporch(t_v_bp), // PIXELS .hsync_width(t_hsync_width), // pixels .vsync_width(t_vsync_width), // PIXELS .lcd_de_latency(t_lcd_de_latency), .lcd_vsync_latency(t_vsync_latency), .refclkcnt(t_refclkcnt) ); `else // !`ifdef TIMING_POSTX // run the timing detector after the Rx mux, so that during self-timed mode we // get the timing of whatever's coming in on the input port. timing_detector timing_det ( .pclk(rx0_pllclk1), // off of the rx clock .rstin(tx0_rstin), .vsync(vsync_v), // vsync_v is polarity-corrrected .hsync(hsync_v), // hsync_v is polarity-corrected .de(de_sync), .refclk(clk26buf), // actually 26 MHz due to PXA168 multipliers .lcd_de(lcdr_de), .lcd_vsync(lcdr_vsync), .hactive(t_hactive), // pixels .vactive(t_vactive), // pixels .htotal(t_htotal), // pixels .vtotal(t_vtotal), // PIXELS .h_frontporch(t_h_fp), // pixels .h_backporch(t_h_bp), // pixels .v_frontporch(t_v_fp), // PIXELS .v_backporch(t_v_bp), // PIXELS .hsync_width(t_hsync_width), // pixels .vsync_width(t_vsync_width), // PIXELS .lcd_de_latency(t_lcd_de_latency), .lcd_vsync_latency(t_vsync_latency), .refclkcnt(t_refclkcnt) ); `endif // !`ifdef TIMING_POSTX ///////////////// // // LCD input & FIFO // ///////////////// // This module will contain the input from the LCD // and a FIFO that can hold a few lines of video data wire dummy; wire genlock; assign VSYNC_STB = genlock & !self_mode; // only genlock when self-mode is off lcd_input lcd_input_top ( .rstin(self_mode ? comp_ctl[4] : rx0_reset), // .lcd_dclk(LCD_DCLK_intbuf), .lcd_dclk(tx0_pclk), .lcd_de(lcdr_de), .lcd_hsync(lcdr_hsync), .lcd_vsync(lcdr_vsync), .lcd_sync_pol(1'b1), .lcd_b(lcdr_b), .lcd_g(lcdr_g), .lcd_r(lcdr_r), .hdmi_pclk(tx0_pclk), .hdmi_de(de_sync), //nuke .hdmi_vsync(tx0_vsync), // .hdmi_hsync(tx0_hsync), .hdmi_vsync(tx0_vsync ^ !hdmi_vsync_pol), .hdmi_hsync(tx0_hsync ^ !hdmi_hsync_pol), .hdmi_sync_pol(1'b1), .hdmi_cv(tx0_cv), .hdmi_b(blend_b), .hdmi_r(blend_r), .hdmi_g(blend_g), .genlock(genlock), .locked(genlock_locked), .dummy(dummy), .line_full_level(line_full_level[2:0]), .line_empty_level(line_empty_level[2:0]), .write_init_level(write_init_level), .read_init_level(read_init_level), .target_lead_pixels(target_lead_pixels), .reset_lock_machine(reset_lock_machine), .lock_tolerance(lock_tolerance), .smartlock_on(smartlock_on) ); assign reset_lock_machine = comp_ctl[6]; assign smartlock_on = comp_ctl[5]; reg hdmi_de_d; wire hdmi_de_rising; reg vsync_v_raw, hsync_v_raw; wire actual_reset; assign actual_reset = self_mode ? comp_ctl[4] : rx0_reset; // hdmi sync polarity detector always @(posedge tx0_pclk or posedge actual_reset) begin if(actual_reset) begin hdmi_vsync_pol <= 0; hdmi_hsync_pol <= 0; vsync_v_raw <= 0; hsync_v_raw <= 0; end else begin hdmi_de_d <= de_sync; if(tx0_cv) begin vsync_v_raw <= tx0_vsync; hsync_v_raw <= tx0_hsync; end else begin vsync_v_raw <= vsync_v_raw; hsync_v_raw <= hsync_v_raw; end // the theory goes that de is always active high so use this to adjust sync polarities if( hdmi_de_rising ) begin hdmi_vsync_pol <= !vsync_v_raw; hdmi_hsync_pol <= !hsync_v_raw; end else begin hdmi_vsync_pol <= hdmi_vsync_pol; hdmi_hsync_pol <= hdmi_hsync_pol; end end end // always @ (posedge hdmi_pclk) assign hdmi_de_rising = !hdmi_de_d & de_sync; `define HDCP_MODULE 1 `ifdef HDCP_MODULE /////// // HDCP /////// // HDCP initialization procedure // // 1. Sniff An, KSV going across the wire // 2. Generate private key table for one of the KSV's // 3. Perform the Km computation using derived private key table // 4. Enter An, Km into the register for the HDCP cipher // 5. Initiate the authentication (pulse hdcpBlockCipher_init and // authentication high one cycle simultaneously) // 6. Wait until stream_ready is high // // Now begins the main loop: // There is an ambiguity in the spec. Either a rekey operation happens immediately // (since this happens during vertical retrace), or not. Either way, this is roughly // what happens. // // 1. If hdcp_ena activates (or of de and data island enable), advance cipher // 2. If vertical sync happens, pulse hdcpBlockCipher_init one cycle and wait // until stream_ready; return to 1 // 3. If horizontal sync happens, pulse hdcpRekeyCipher once cycle, wait until // stream_ready; return to 1 // // That's it. So the only question is if vsync "happens" immediately after an authentication. // The test vectors would suggest this is the case but I can't find it in the state machine // diagrams, so perhaps good to try both options...? parameter HDCP_UNPLUG = 18'b1 << 0; parameter HDCP_WAIT_AKSV = 18'b1 << 1; parameter HDCP_AUTH_PULSE = 18'b1 << 2; parameter HDCP_AUTH = 18'b1 << 3; parameter HDCP_AUTH_WAIT = 18'b1 << 4; parameter HDCP_AUTH_VSYNC_PULSE = 18'b1 << 5; parameter HDCP_AUTH_VSYNC = 18'b1 << 6; parameter HDCP_AUTH_VSYNC_WAIT = 18'b1 << 7; parameter HDCP_WAIT_1001 = 18'b1 << 8; parameter HDCP_WAIT_1001_END = 18'b1 << 9; parameter HDCP_VSYNC = 18'b1 << 10; parameter HDCP_VSYNC_PULSE = 18'b1 << 11; parameter HDCP_VSYNC_WAIT = 18'b1 << 12; parameter HDCP_READY = 18'b1 << 13; parameter HDCP_REKEY = 18'b1 << 14; parameter HDCP_REKEY_PULSE = 18'b1 << 15; parameter HDCP_REKEY_WAIT = 18'b1 << 16; parameter HDCP_WAIT_KMRDY = 18'b1 << 17; parameter HDCP_nSTATES = 18; reg [(HDCP_nSTATES-1):0] HDCP_cstate = {{(HDCP_nSTATES-1){1'b0}}, 1'b1}; reg [(HDCP_nSTATES-1):0] HDCP_nstate; reg auth_mode; reg hdcp_init; reg hdcp_rekey; wire hdcp_stream_ena; reg active_line; reg hdcp_rekey_2; reg hdcp_rekey_1; assign hdcp_is_ready = (HDCP_cstate == HDCP_READY); // compute active_line. This tells you if the last line had active data // in it or not. Reset the computation on falling edge of hsync always @ (posedge tx0_pclk or posedge tx0_reset) begin if( tx0_reset == 1'b1 ) begin active_line <= 1'b0; hdcp_rekey_2 <= 1'b0; hdcp_rekey_1 <= 1'b0; end else begin hdcp_rekey_2 <= hdcp_rekey_1; hdcp_rekey_1 <= hdcp_rekey || (rx0_line_end && (HDCP_cstate == HDCP_READY) && tx0_de); if( tx0_de ) begin active_line <= 1'b1; end else if( !hsync_v & hsync_v2 ) begin // hsync falling active_line <= 1'b0; end end end always @ (posedge tx0_pclk or posedge HPD_N or posedge tx0_reset or negedge rstbtn_n) begin if (~rstbtn_n | HPD_N | tx0_reset ) HDCP_cstate <= HDCP_UNPLUG; else if( Aksv14_write ) begin HDCP_cstate <= HDCP_AUTH_PULSE; // hack for tivo series 3 end else begin HDCP_cstate <=#1 HDCP_nstate; end end always @ (*) begin case (HDCP_cstate) //synthesis parallel_case full_case HDCP_UNPLUG: begin HDCP_nstate = HPD_N ? HDCP_UNPLUG : HDCP_WAIT_AKSV; end HDCP_WAIT_AKSV: begin // wait until the 14th byte is written to the HDCP register set // this is the MSB of AKsv, and this triggers an authentication event HDCP_nstate = Aksv14_write ? HDCP_AUTH_PULSE : HDCP_WAIT_AKSV; // HDCP_nstate = Aksv14_write ? HDCP_WAIT_KMRDY : HDCP_WAIT_AKSV; // in this implementation, skipe the HDCP_WAIT_KMRDY state end // this state is unreachable HDCP_WAIT_KMRDY: begin HDCP_nstate = Km_ready ? HDCP_AUTH_PULSE : HDCP_WAIT_KMRDY; end //////// // maybe put a state here to wait for Km to become ready // but for now, we assume host has pre-loaded Km. Km is fixed for every Tx/Rx HDMI pair. // So once you have computed it, it can be pre-loaded even before the transaction happens. // One way around this is to snag AKsv, Bksv; and if they are a new pair, compute Km // and load it; and then override HPD_N high for a second to force a re-key *only* if // this is new pair. Thus, the first time you plug in a new device you *might* see it // flicker once, but it would never happen again, but I think typically you would // not notice because the screen would stay dark the entire time. // // --> above is the wait KMRDY state. The way this should work now is: // 1. Aksv is written, byte 14 triggers an interrupt to the CPU. // 2. CPU derives Km, writes Km, sets Km ready // 3. state machine then moves on to initiate auth pulse // //////// HDCP_AUTH_PULSE: begin HDCP_nstate = HDCP_AUTH; end HDCP_AUTH: begin HDCP_nstate = stream_ready? HDCP_AUTH : HDCP_AUTH_WAIT; end HDCP_AUTH_WAIT: begin HDCP_nstate = stream_ready ? HDCP_AUTH_VSYNC_PULSE : HDCP_AUTH_WAIT; end // this is a special vsync-update state just for after auth // because I don't know if there is more than 1 vsync period between // the conclusion of auth and the first 1001 assertion // if there is, then we end up unsynchronized on the Mi state HDCP_AUTH_VSYNC_PULSE: begin HDCP_nstate = HDCP_AUTH_VSYNC; end HDCP_AUTH_VSYNC: begin HDCP_nstate = stream_ready ? HDCP_AUTH_VSYNC : HDCP_AUTH_VSYNC_WAIT; end HDCP_AUTH_VSYNC_WAIT: begin HDCP_nstate = stream_ready ? HDCP_WAIT_1001 : HDCP_AUTH_VSYNC_WAIT; end // our primary wait state HDCP_WAIT_1001: begin HDCP_nstate = (vsync_v && (rx0_ctl_code[3:0] == 4'b1001)) ? HDCP_WAIT_1001_END : HDCP_WAIT_1001; end HDCP_WAIT_1001_END: begin HDCP_nstate = (vsync_v && (rx0_ctl_code[3:0] == 4'b1001)) ? HDCP_WAIT_1001_END : HDCP_READY; end HDCP_VSYNC_PULSE: begin HDCP_nstate = HDCP_VSYNC; end HDCP_VSYNC: begin HDCP_nstate = stream_ready ? HDCP_VSYNC : HDCP_VSYNC_WAIT; end HDCP_VSYNC_WAIT: begin HDCP_nstate = stream_ready ? HDCP_WAIT_1001 : HDCP_VSYNC_WAIT; end // our primary cipher state HDCP_READY: begin // HDCP_nstate = (!rx0_de & tx0_de) ? HDCP_REKEY_PULSE : // i've now got a signal banging rekey outside this state machine // it's unclean, but necessary to get rekey to happen early enough // to meet hdcp spec requirement for rekey time. // Core assumption: the only way stream becomes un-ready during // HDCP_READY is due to the external rekey event. vsync_rising // will never result in this triggering because it itself must // transition this state machine to a new state before stream_ready // changes; and furthermore, stream_ready is guaranteed to be high // upon return to this state. HDCP_nstate = (stream_ready == 1'b0) ? HDCP_REKEY_WAIT : vsync_rising ? HDCP_VSYNC_PULSE : HDCP_READY; end HDCP_REKEY_PULSE: begin HDCP_nstate = HDCP_REKEY; end HDCP_REKEY: begin HDCP_nstate = stream_ready ? HDCP_REKEY : HDCP_REKEY_WAIT; end HDCP_REKEY_WAIT: begin HDCP_nstate = stream_ready ? HDCP_READY : HDCP_REKEY_WAIT; end endcase // case (HDCP_cstate) end // assign Km_ready = !Km_rdy2 & Km_rdy1; // rising edge pulse assign Km_ready = Km_rdy2; // for now make it level triggered ("cheezy mode") always @ (posedge tx0_pclk or posedge HPD_N or posedge tx0_reset or negedge rstbtn_n) begin if( ~rstbtn_n | HPD_N | tx0_reset ) begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; Km_rdy0 <= 1'b0; Km_rdy1 <= 1'b0; Km_rdy2 <= 1'b0; end else begin Km_rdy0 <= comp_ctl[7]; Km_rdy1 <= Km_rdy0; Km_rdy2 <= Km_rdy1; case (HDCP_cstate) //synthesis parallel_case full_case HDCP_UNPLUG: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_WAIT_AKSV: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_WAIT_KMRDY: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH_PULSE: begin auth_mode <=#1 1'b1; hdcp_init <=#1 1'b1; // pulse just one cycle hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH_WAIT: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH_VSYNC_PULSE: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b1; // pulse init, but not with auth_mode hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH_VSYNC: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_AUTH_VSYNC_WAIT: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_WAIT_1001: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_WAIT_1001_END: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b0; end HDCP_VSYNC_PULSE: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b1; // pulse init, but not with auth_mode hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end HDCP_VSYNC: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end HDCP_VSYNC_WAIT: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end HDCP_READY: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end HDCP_REKEY_PULSE: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; // hdcp_rekey <=#1 1'b1; // pulse rekey hdcp_rekey <=#1 1'b0; // we're going to do this asychronously to save some cycles // yes, it means hdcp_rekey gets optimized out // but structurally this helps me remember what the code was intended to do hdcp_requested <=#1 1'b1; end HDCP_REKEY: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end HDCP_REKEY_WAIT: begin auth_mode <=#1 1'b0; hdcp_init <=#1 1'b0; hdcp_rekey <=#1 1'b0; hdcp_requested <=#1 1'b1; end endcase // case (HDCP_cstate) end // else: !if( ~rstbtn_n | HPD_N ) end // always @ (posedge tx0_pclk) wire stream_ready; hdcp_cipher cipher ( .clk(tx0_pclk), .reset(tx0_rstin), .Km(Km), .An(An), .hdcpBlockCipher_init(hdcp_init), .authentication(auth_mode), .hdcpRekeyCipher(hdcp_rekey_2), .hdcpStreamCipher(rx0_hdcp_ena && (HDCP_cstate == HDCP_READY)), .pr_data(cipher_stream), .stream_ready(stream_ready) ); `endif // `ifdef HDCP_MODULE ////////////////////////////////////// // Status LED ////////////////////////////////////// reg [22:0] counter; always @(posedge clk26buf or negedge rstbtn_n) begin if( rstbtn_n == 1'b0 ) begin counter <= 1'b0; LED0 <= 1'b0; end else begin counter <= counter + 1; // LED <= counter[22] & !rx0_de; // LED <= counter[22] & byp_error | dummy; // LED <= counter[22] & dummy; // LED0 <= dummy & snoop_ctl[7]; `ifdef PASSTHROUGH // LED0 <= dummy; LED0 <= vsync_v; `else // LED0 <= tx0_plllckd && m720p_locked & ss_locked; `endif // LED1 <= counter[22]; // LED1 <= de_sync; end // else: !if( rstbtn_n == 1'b0 ) LOWVOLT_NOTIFY <= LOWVOLT_N; HDCP_AKSV <= Aksv14_write; // retime it into this domain to not screw up timing closure end //assign LED[3:0] = {rx0_red_rdy | counter[23], rx0_green_rdy | counter[23], rx0_blue_rdy | counter[23], // rx0_de | counter[23]}; //////////////////////////////// // serial number //////////////////////////////// reg clk2M_unbuf; (* clock_signal = "yes" *) (* PERIOD = "period 0.8125 MHz" *) wire clk2M; wire clk1M; reg clk1M_unbuf; always @(posedge clk26buf) begin clk2M_unbuf <= counter[4]; // 0.8MHz clock: device DNA only runs at 2 MHz clk1M_unbuf <= counter[6]; end BUFG clk2M_buf(.I(clk2M_unbuf), .O(clk2M)); BUFG clk1M_buf(.I(clk1M_unbuf), .O(clk1M)); reg dna_pulse; reg dna_shift; wire dna_bit; DNA_PORT device_dna( .CLK(clk2M), .DIN(1'b0), .DOUT(dna_bit), .READ(dna_pulse), .SHIFT(dna_shift) ); parameter DNA_INIT = 4'b1 << 0; parameter DNA_PULSE = 4'b1 << 1; parameter DNA_SHIFT = 4'b1 << 2; parameter DNA_DONE = 4'b1 << 3; parameter DNA_nSTATES = 4; reg [(DNA_nSTATES-1):0] DNA_cstate = {{(DNA_nSTATES-1){1'b0}}, 1'b1}; reg [(DNA_nSTATES-1):0] DNA_nstate; reg [5:0] dna_shift_count; always @ (negedge clk2M or posedge ~rstbtn_n) begin if (~rstbtn_n) DNA_cstate <= DNA_INIT; else DNA_cstate <=#1 DNA_nstate; end always @ (*) begin case (DNA_cstate) //synthesis paralell_case full_case DNA_INIT: begin DNA_nstate = DNA_PULSE; end DNA_PULSE: begin DNA_nstate = DNA_SHIFT; end DNA_SHIFT: begin // depending on if MSB or LSB first, want to use 56 or 55 // especially if serial #'s are linear-incrementing DNA_nstate = (dna_shift_count[5:0] == 6'd55) ? DNA_DONE : DNA_SHIFT; end DNA_DONE: begin DNA_nstate = DNA_DONE; end endcase // case (DNA_cstate) end always @ (negedge clk2M or posedge ~rstbtn_n) begin if( ~rstbtn_n ) begin dna_shift_count <= 6'h0; dna_data <= 56'h0; dna_pulse <= 1'b0; dna_shift <= 1'b0; end else begin case (DNA_cstate) //synthesis paralell_case full_case DNA_INIT: begin dna_shift_count <= 6'h0; dna_data <= 56'h0; dna_pulse <= 1'b0; dna_shift <= 1'b0; end DNA_PULSE: begin dna_shift_count <= 6'h0; dna_data <= 56'h0; dna_pulse <= 1'b1; dna_shift <= 1'b0; end DNA_SHIFT: begin dna_shift_count <= dna_shift_count + 6'b1; dna_data[55:0] <= {dna_data[54:0],dna_bit}; dna_pulse <= 1'b0; dna_shift <= 1'b1; end DNA_DONE: begin dna_shift_count <= dna_shift_count; dna_data[55:0] <= dna_data[55:0]; dna_pulse <= 1'b0; dna_shift <= 1'b0; end endcase // case (DNA_cstate) end // else: !if( ~rstbtn_n ) end // always @ (posedge clk2M or posedge ~rstbtn_n) //////////////////////////////// // heartbeat //////////////////////////////// pwm heartbeat(.clk812k(clk1M), .reset(~rstbtn_n), .pwmout(blue_led), .bright(12'b0000_1111_1000), .dim(12'b0000_0001_0000) ); assign LED1 = blue_led | HPD_N; endmodule