// ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014
 
//
 
// generates horizontal sync, blank and video start strobe, horizontal window
 
 
 
/*
 
    This file is part of ZX-Evo Base Configuration firmware.
 
 
 
    ZX-Evo Base Configuration firmware is free software:
 
    you can redistribute it and/or modify it under the terms of
 
    the GNU General Public License as published by
 
    the Free Software Foundation, either version 3 of the License, or
 
    (at your option) any later version.
 
 
 
    ZX-Evo Base Configuration firmware 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 General Public License for more details.
 
 
 
    You should have received a copy of the GNU General Public License
 
    along with ZX-Evo Base Configuration firmware.
 
    If not, see <http://www.gnu.org/licenses/>.
 
*/
 
 
 
//
 
// =\                  /=========||...
 
// ==\                /==========||...
 
// ====---     -------===========||...
 
//    |  \   / |      |
 
//    |   ---  |      |
 
//    |  |   | |      |
 
//    0  t1  | t3     t4
 
//           t2
 
// at 0, video ends and blank begins
 
//    t1 = 10 clocks (@7MHz), sync begins
 
// t2-t1 = 33 clocks
 
// t3-t2 = 41 clocks, then video starts
 
//
 
// repetition period = 448 clocks
 
 
 
`include "../include/tune.v"
 
 
 
module video_sync_h(
 
 
 
        input  wire        clk,
 
 
 
        input  wire        init, // one-pulse strobe read at cend==1, initializes phase
 
                                 // this is mainly for phasing with CPU clock 3.5/7 MHz
 
                                 // still not used, but this may change anytime
 
 
 
        input  wire        cend,     // working strobes from DRAM controller (7MHz)
 
        input  wire        pre_cend,
 
 
 
 
 
        // modes inputs
 
        input  wire        mode_atm_n_pent,
 
        input  wire        mode_a_text,
 
 
 
        input  wire [ 1:0] modes_raster,
 
        input  wire        mode_contend_type, 
 
 
 
        output reg         hblank,
 
        output reg         hsync,
 
 
 
        output reg         line_start,  // 1 video cycle prior to actual start of visible line
 
        output reg         hsync_start, // 1 cycle prior to beginning of hsync: used in frame sync/blank generation
 
                                        // these signals coincide with cend
 
 
 
        output reg         hint_start, // horizontal position of INT start, for fine tuning
 
 
 
        output reg         scanin_start,
 
 
 
        input  wire        vpix,
 
        output reg         hpix, // marks gate during which pixels are outting
 
 
 
        output reg         contend, // for 48k/128k CPU contention
 
 
 
        output reg         border_sync, // for 48k/128k 4t border emulation
 
 
 
                                        // these signals turn on and turn off 'go' signal
 
        output reg         fetch_start, // 18 cycles earlier than hpix, coincide with cend
 
        output reg         fetch_end    // --//--
 
 
 
);
 
 
 
 
 
        localparam HBLNK_BEG = 9'd00;
 
        localparam HSYNC_BEG = 9'd10;
 
        localparam HSYNC_END = 9'd43;
 
        localparam HBLNK_END = 9'd88;
 
 
 
        // pentagon (x256)
 
        localparam HPIX_BEG_PENT = 9'd140; // 52 cycles from line_start to pixels beginning
 
        localparam HPIX_END_PENT = 9'd396;
 
 
 
        // atm (x320)
 
        localparam HPIX_BEG_ATM = 9'd108; // 52 cycles from line_start to pixels beginning
 
        localparam HPIX_END_ATM = 9'd428;
 
 
 
 
 
        localparam FETCH_FOREGO = 9'd18; // consistent with older go_start in older fetch.v:
 
                                         // actual data starts fetching 2 dram cycles after
 
                                         // 'go' goes to 1, screen output starts another
 
                                         // 16 cycles after 1st data bundle is fetched
 
 
 
 
 
        localparam SCANIN_BEG = 9'd88; // when scan-doubler starts pixel storing
 
 
 
 
 
        localparam HINT_BEG      = 9'd2;
 
        localparam HINT_BEG_48K  = 9'd126;
 
        localparam HINT_BEG_128K = 9'd130;
 
 
 
 
 
        localparam HPERIOD_224 = 9'd448;
 
        localparam HPERIOD_228 = 9'd456;
 
 
 
 
 
        localparam CONTEND_START = 9'd127; // fixed for correct contend phase: coincides with positive edge of z80 clock
 
        //localparam CONTEND_START_48K  = 9'd132;
 
        //localparam CONTEND_START_128K = 9'd132;
 
 
 
 
 
        localparam BORDER_PHASE = 3'd4;
 
 
 
 
 
        reg [8:0] hcount;
 
 
 
        reg [8:0] contend_ctr;
 
 
 
        // for simulation only
 
        //
 
        initial
 
        begin
 
                hcount = 9'd0;
 
                hblank = 1'b0;
 
                hsync = 1'b0;
 
                line_start = 1'b0;
 
                hsync_start = 1'b0;
 
                hpix = 1'b0;
 
        end
 
 
 
 
 
 
 
 
 
        always @(posedge clk) if( cend )
 
        begin
 
            if(  init || hcount==( (modes_raster==2'b11) ? (HPERIOD_228-9'd1) : (HPERIOD_224-9'd1) )  )
 
                hcount <= 9'd0;
 
            else
 
                hcount <= hcount + 9'd1;
 
        end
 
 
 
 
 
 
 
        always @(posedge clk) if( cend )
 
        begin
 
                if( hcount==HBLNK_BEG )
 
                        hblank <= 1'b1;
 
                else if( hcount==HBLNK_END )
 
                        hblank <= 1'b0;
 
 
 
 
 
                if( hcount==HSYNC_BEG )
 
                        hsync <= 1'b1;
 
                else if( hcount==HSYNC_END )
 
                        hsync <= 1'b0;
 
        end
 
 
 
 
 
        always @(posedge clk)
 
        begin
 
                if( pre_cend )
 
                begin
 
                        if( hcount==HSYNC_BEG )
 
                                hsync_start <= 1'b1;
 
 
 
                        if( hcount==HBLNK_END )
 
                                line_start <= 1'b1;
 
 
 
                        if( hcount==SCANIN_BEG )
 
                                scanin_start <= 1'b1;
 
 
 
                end
 
                else
 
                begin
 
                        hsync_start  <= 1'b0;
 
                        line_start   <= 1'b0;
 
                        scanin_start <= 1'b0;
 
                end
 
        end
 
 
 
 
 
 
 
        wire fetch_start_time, fetch_start_condition;
 
        wire fetch_end_condition;
 
 
 
        reg [3:0] fetch_start_wait;
 
 
 
 
 
        assign fetch_start_time = (mode_atm_n_pent                  ?
 
                                  (HPIX_BEG_ATM -FETCH_FOREGO-9'd4) :
 
                                  (HPIX_BEG_PENT-FETCH_FOREGO-9'd4) ) == hcount;
 
 
 
        always @(posedge clk) if( cend )
 
                fetch_start_wait[3:0] <= { fetch_start_wait[2:0], fetch_start_time };
 
 
 
        assign fetch_start_condition = mode_a_text ? fetch_start_time  : fetch_start_wait[3];
 
 
 
        always @(posedge clk)
 
        if( pre_cend && fetch_start_condition )
 
                fetch_start <= 1'b1;
 
        else
 
                fetch_start <= 1'b0;
 
 
 
 
 
 
 
 
 
        assign fetch_end_time = (mode_atm_n_pent             ?
 
                                (HPIX_END_ATM -FETCH_FOREGO) :
 
                                (HPIX_END_PENT-FETCH_FOREGO) ) == hcount;
 
 
 
        always @(posedge clk)
 
        if( pre_cend && fetch_end_time )
 
                fetch_end <= 1'b1;
 
        else
 
                fetch_end <= 1'b0;
 
 
 
 
 
 
 
 
 
 
 
        always @(posedge clk)
 
        begin
 
                if( pre_cend && hcount==( modes_raster[1] ? (modes_raster[0] ? HINT_BEG_128K : HINT_BEG_48K) : HINT_BEG ) )
 
                        hint_start <= 1'b1;
 
                else
 
                        hint_start <= 1'b0;
 
        end
 
 
 
 
 
        always @(posedge clk) if( cend )
 
        begin
 
                if( hcount==(mode_atm_n_pent ? HPIX_BEG_ATM : HPIX_BEG_PENT) )
 
                        hpix <= 1'b1;
 
                else if( hcount==(mode_atm_n_pent ? HPIX_END_ATM : HPIX_END_PENT) )
 
                        hpix <= 1'b0;
 
        end
 
 
 
 
 
 
 
        // contention generator
 
        initial
 
                contend_ctr <=9'h100;
 
        //
 
        always @(posedge clk) if( cend )
 
        begin
 
                if( hcount == CONTEND_START )
 
                        contend_ctr <= 9'd0;
 
                else if( !contend_ctr[8] )
 
                        contend_ctr <= contend_ctr + 9'd1;
 
        end
 
        //
 
        //
 
        always @(posedge clk) if( cend )
 
        begin
 
                if( contend_ctr[8] || !vpix )
 
                        contend <= 1'b0;
 
                else if( !mode_contend_type )
 
                // 48k type contention
 
                case( contend_ctr[3:1] )
 
                        3'd6,
 
                        3'd7:    contend <= 1'b0;
 
                        default: contend <= 1'b1;
 
                endcase
 
                else
 
                // +2a/+3 type contention
 
                case( contend_ctr[3:1] )
 
                        3'd1:    contend <= 1'b0;
 
                        default: contend <= 1'b1;
 
                endcase
 
                //
 
                // warning! probably +2a/+3 contention pattern is incorrect, it begins with 1 cycle contention but probably should end
 
                //  with one extra contention cycle. Anyway this is left as TODO.
 
                //
 
        end
 
 
 
 
 
 
 
        // border sync signal gen
 
        always @(posedge clk)
 
        if( pre_cend && hcount[2:0]==BORDER_PHASE )
 
                border_sync <= 1'b1;
 
        else
 
                border_sync <= 1'b0;
 
                
 
 
 
 
 
endmodule