// PentEvo project (c) NedoPC 2008-2011
//
// Z80 clocking module, also contains some wait-stating when 14MHz
//
// IDEAL:
// clk    _/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\_/`\
//          |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
// zclk     /```\___/```\___/```\___/```````\_______/```````\_______/```````````````\_______________/```````````````\_______________/`
//          |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
// zpos     `\___/```\___/```\___/```\___________/```\___________/```\___________________________/```\___________________________/```\
//          |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |   |
// zneg     _/```\___/```\___/```\_______/```\___________/```\___________________/```\___________________________/```\________________

// clock phasing:
// c3 must be zpos for 7mhz, therefore c1 - zneg
// for 3.5 mhz, c3 is both zpos and zneg (alternating)


// 14MHz rulez:
// 1. do variable stalls for memory access.
// 2. do fallback on 7mhz for external IO accesses
// 3. clock switch 14-7-3.5 only at RFSH

`include "tune.v"

module zclock
(
  input             clk,
  output reg        zclk_out = 0,   // generated Z80 clock, passed through inverter externally
  input             c0, c2,

  input wire        iorq_s,
  input wire        external_port,

  output reg        zpos,
  output reg        zneg,

// stall enables and triggers
  input  wire       cpu_stall,
  input  wire       ide_stall,
  input  wire       dos_on,
  input  wire       vdos_off,

`ifdef PENT_312
  input  wire       boost_start,
  input  wire [4:0] hcnt,
  input  wire       upper8,
`endif

  input [1:0]       turbo   // 2'b00 -  3.5 MHz
                            // 2'b01 -  7.0 MHz
                            // 2'b1x - 14.0 MHz
);

`ifdef PENT_312
// Turbo-boost for Pentagon 71680 tacts emulation with 312 video lines
  wire [1:0] turbo_int = (turbo == 2'b00) ? (t_boost ? 2'b01 : 2'b00) : turbo;
  reg t_boost = 0;
  reg [4:0] hcnt_r = 0;
  always @(posedge clk)
    if (boost_start && !t_boost)
    begin
      t_boost <= 1'b1;
      hcnt_r <= hcnt;
    end
    else if (t_boost && !upper8 && (hcnt_r == hcnt))
      t_boost <= 1'b0;
`else
  wire [1:0] turbo_int = turbo;
`endif

// wait generator
  reg [3:0] stall_count = 0;

  wire dos_stall = dos_on || vdos_off;
  wire io_stall = iorq_s && external_port && turbo_int[1];
  wire stall_start = dos_stall || io_stall;
  wire stall_count_end = stall_count[3];
  wire dos_io_stall = stall_start || !stall_count_end;

  always @(posedge clk)
    if (stall_start)
    begin
      if (dos_stall)
        stall_count <= 4'd4;  // 4 tacts 28MHz (1 tact 7MHz)
      else if (io_stall)
        stall_count <= 4'd0;  // 8 tacts 28MHz (1 tact 3.5MHz)
    end
    else if (!stall_count_end)
      stall_count <= stall_count + 3'd1;

// Z80 clocking pre-strobes
  reg clk14_src = 0;  // source for 14MHz clock
  reg c2_cnt = 0;

  wire stall = cpu_stall || dos_io_stall || ide_stall;

  wire pre_zpos_140 = clk14_src;
  wire pre_zneg_140 = ~clk14_src;

  wire pre_zpos_70 = c2;
  wire pre_zneg_70 = c0;

  wire pre_zpos_35 = c2_cnt && c2;
  wire pre_zneg_35 = !c2_cnt && c2;

  wire pre_zpos = turbo_int[1] ? pre_zpos_140 : (turbo_int[0] ? pre_zpos_70 : pre_zpos_35);
  wire pre_zneg = turbo_int[1] ? pre_zneg_140 : (turbo_int[0] ? pre_zneg_70 : pre_zneg_35);

  always @(posedge clk)
  if (!stall)
    clk14_src <= ~clk14_src;

  always @(posedge clk) if (c2)
    c2_cnt <= ~c2_cnt;

// Z80 clocking strobes
  always @(posedge clk)
  begin
    zpos <= !stall && pre_zpos && zclk_out;
    zneg <= !stall && pre_zneg && !zclk_out;
  end

  // make Z80 clock: account for external inversion and make some leading of clock
  // 9.5 ns propagation delay: from clk posedge to zclk returned back any edge
  // (1/28)/2=17.9ns half a clock lead
  // 2.6ns lag because of non-output register emitting of zclk_out
  // total: 5.8 ns lead of any edge of zclk relative to posedge of clk => ACCOUNT FOR THIS WHEN DOING INTER-CLOCK DATA TRANSFERS

  // Z80 clocking
  always @(negedge clk)
  begin
    if (zpos)
      zclk_out <= 1'b0;

    if (zneg)
      zclk_out <= 1'b1;
  end

endmodule
