
`include "tune.v"

module zint
(
  input  wire       clk,
  input  wire       zpos,
  input  wire       res,
  input  wire       wait_n,
  input  wire       int_start_frm,
  input  wire       int_start_lin,
  input  wire       int_start_dma,
  input  wire       int_start_wtp,
  input  wire       vdos,           // pre_vdos
  input  wire       intack,
`ifdef PENT_312
  output wire       boost_start,
`endif

  input  wire [7:0] intmask,
  output wire [7:0] im2vect,

  output wire int_n
);

  // In VDOS INTs are focibly disabled.
  // For Frame, Line INT its generation is blocked, it will be lost.
  // For DMA INT only its output is blocked, so DMA ISR will will be processed as soon as returned from VDOS.

  reg [1:0] int_sel = 0;
  reg int_frm;
  reg int_dma;
  reg int_lin;
  reg int_wtp;
  reg intack_r;
  wire intctr_fin;
  
  localparam INTFRM = 2'b00;
  localparam INTLIN = 2'b01;
  localparam INTDMA = 2'b10;
  localparam INTWTP = 2'b11;

  wire [7:0] vect [0:3];
  assign vect[INTFRM] = 8'hFF;
  assign vect[INTLIN] = 8'hFD;
  assign vect[INTDMA] = 8'hFB;
  assign vect[INTWTP] = 8'hF9;

  assign im2vect = {vect[int_sel]};

  wire int_all = (int_frm || int_lin || int_dma || int_wtp) && !vdos;
  assign int_n = int_all ? 1'b0 : 1'b1;

  wire dis_int_frm = !intmask[0];
  wire dis_int_lin = !intmask[1];
  wire dis_int_dma = !intmask[2];
  wire dis_int_wtp = !intmask[3];

`ifdef PENT_312
  assign boost_start = intack_s || intctr_fin_s;

  wire intctr_fin_s = !intctr_fin_r && intctr_fin;
  reg intctr_fin_r;
  always @(posedge clk)
    intctr_fin_r <= intctr_fin;
`endif

  wire intack_s = intack && !intack_r;
  always @(posedge clk)
    intack_r <= intack;

// ~INT source latch
  always @(posedge clk)
    if (intack_s)
    begin
      if (int_frm)
        int_sel <= INTFRM;    // priority 0
      else if (int_lin)
        int_sel <= INTLIN;    // priority 1
      else if (int_dma)
        int_sel <= INTDMA;    // priority 2
      else if (int_wtp)
        int_sel <= INTWTP;    // priority 3
    end

// ~INT generating
  always @(posedge clk)
    if (res || dis_int_frm)
      int_frm <= 1'b0;
    else if (int_start_frm)
      int_frm <= 1'b1;
    else if (intack_s || intctr_fin)    // priority 0
      int_frm <= 1'b0;

  always @(posedge clk)
    if (res || dis_int_lin)
      int_lin <= 1'b0;
    else if (int_start_lin)
      int_lin <= 1'b1;
    else if (intack_s && !int_frm)    // priority 1
      int_lin <= 1'b0;

  always @(posedge clk)
    if (res || dis_int_dma)
      int_dma <= 1'b0;
    else if (int_start_dma)
      int_dma <= 1'b1;
    else if (intack_s && !int_frm && !int_lin)    // priority 2
      int_dma <= 1'b0;

  always @(posedge clk)
    if (res || dis_int_wtp)
      int_wtp <= 1'b0;
    else if (int_start_wtp)
      int_wtp <= 1'b1;
    else if (intack_s && !int_frm && !int_lin && !int_dma)    // priority 3
      int_wtp <= 1'b0;

// ~WAIT resync
  reg wait_r;
    always @(posedge clk)
        wait_r <= !wait_n;

// ~INT counter
  reg [5:0] intctr;
  assign intctr_fin = intctr[5];   // 32 clks

  always @(posedge clk, posedge int_start_frm)
  begin
    if (int_start_frm)
      intctr <= 1'b0;
    else if (zpos && !intctr_fin && !wait_r && !vdos)
      intctr <= intctr + 1'b1;
  end

endmodule
