
// PentEvo project (c) NedoPC 2008-2010

`include "tune.v"

module zports
(
  input  wire        zclk,    // z80 clock
  input  wire        clk,

  input  wire [ 7:0] din,
  output reg  [ 7:0] dout,
  output wire        dataout,
  input  wire [15:0] a,

  input  wire        rst,     // system reset
  input  wire        opfetch,

  input  wire        rd,
  input  wire        wr,
  input  wire        rdwr,

  input  wire        iorq,
  input  wire        iorq_s,
  input  wire        iord,
  input  wire        iord_s,
  input  wire        iowr,
  input  wire        iowr_s,
  input  wire        iordwr,
  input  wire        iordwr_s,

  output wire        porthit,       // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
  output wire        external_port, // asserts for AY and VG93 accesses

  output wire        zborder_wr,
  output wire        border_wr,
  output wire        zvpage_wr,
  output wire        vpage_wr,
  output wire        vconf_wr,
  output wire        gx_offsl_wr,
  output wire        gx_offsh_wr,
  output wire        gy_offsl_wr,
  output wire        gy_offsh_wr,
  output wire        t0x_offsl_wr,
  output wire        t0x_offsh_wr,
  output wire        t0y_offsl_wr,
  output wire        t0y_offsh_wr,
  output wire        t1x_offsl_wr,
  output wire        t1x_offsh_wr,
  output wire        t1y_offsl_wr,
  output wire        t1y_offsh_wr,
  output wire        tsconf_wr,
  output wire        palsel_wr,
  output wire        tmpage_wr,
  output wire        t0gpage_wr,
  output wire        t1gpage_wr,
  output wire        sgpage_wr,
  output wire        hint_beg_wr,
  output wire        vint_begl_wr,
  output wire        vint_begh_wr,

  output wire [31:0] xt_page,

  output reg [4:0]   fmaddr,
  input  wire        regs_we,

  output reg [7:0]   sysconf,
  output reg [7:0]   memconf,
  output reg [3:0]   cacheconf,
  input  wire        cfg_floppy_swap,
  output reg [7:0]   fddvirt,

`ifdef FDR
  output reg         fdr_en,
  output wire        fdr_cnt_lat,
  input wire [18:0]  fdr_cnt,

  output wire [9:0]  dmaport_wr,
`else
  output wire [8:0]  dmaport_wr,
`endif
  input  wire        dma_act,
  output reg [1:0]   dmawpdev,


  output reg [7:0]   intmask,

  input  wire        dos,
  input  wire        vdos,
  output  wire       vdos_on,
  output  wire       vdos_off,

  output wire        ay_bdir,
  output wire        ay_bc1,
  output wire        covox_wr,
  output wire        beeper_wr,

  input  wire        tape_read,

`ifdef IDE_HDD
  // IDE interface
  input  wire [15:0] ide_in,
  output wire [15:0] ide_out,
  output wire        ide_cs0_n,
  output wire        ide_cs1_n,
  output wire        ide_req,
  input  wire        ide_stb,
  input  wire        ide_ready,
  output reg         ide_stall,
`endif

  input  wire [ 4:0] keys_in, // keys (port FE)
  input  wire [ 7:0] mus_in,  // mouse (xxDF)

`ifdef KEMPSTON_8BIT
  input  wire [ 7:0] kj_in,
`else
  input  wire [ 4:0] kj_in,
`endif

  input  wire        vg_intrq,
  input  wire        vg_drq,  // from vg93 module - drq + irq read
  output wire        vg_cs_n,
  output wire        vg_wrFF,
  output wire [1:0]  drive_sel,    // disk drive selection

  // SPI
  output wire        sdcs_n,
  output wire        sd2cs_n,
`ifdef IDE_VDAC2
  output wire        ftcs_n,
`ifdef ESP32_SPI
  output wire        espcs_n,
`endif
`endif
  output reg         spi_mode,
  output wire        sd_start,
  output wire [ 7:0] sd_datain,
  input  wire [ 7:0] sd_dataout,

  // WAIT-ports related
  output reg  [ 7:0] wait_addr,
  output wire        wait_start_gluclock, // begin wait from some ports
  output wire        wait_start_comport,  //
  output reg  [ 7:0] wait_write,
  input  wire [ 7:0] wait_read
);

  //#nnAF
  localparam VCONF     = 8'h00;
  localparam VPAGE     = 8'h01;
  localparam GXOFFSL   = 8'h02;
  localparam GXOFFSH   = 8'h03;
  localparam GYOFFSL   = 8'h04;
  localparam GYOFFSH   = 8'h05;
  localparam TSCONF    = 8'h06;
  localparam PALSEL    = 8'h07;
  localparam XBORDER   = 8'h0F;

  localparam T0XOFFSL  = 8'h40;
  localparam T0XOFFSH  = 8'h41;
  localparam T0YOFFSL  = 8'h42;
  localparam T0YOFFSH  = 8'h43;
  localparam T1XOFFSL  = 8'h44;
  localparam T1XOFFSH  = 8'h45;
  localparam T1YOFFSL  = 8'h46;
  localparam T1YOFFSH  = 8'h47;

  localparam RAMPAGE   = 8'h10;  // this covers #10-#13
  localparam FMADDR    = 8'h15;
  localparam TMPAGE    = 8'h16;
  localparam T0GPAGE   = 8'h17;
  localparam T1GPAGE   = 8'h18;
  localparam SGPAGE    = 8'h19;
  localparam DMASADDRL = 8'h1A;
  localparam DMASADDRH = 8'h1B;
  localparam DMASADDRX = 8'h1C;
  localparam DMADADDRL = 8'h1D;
  localparam DMADADDRH = 8'h1E;
  localparam DMADADDRX = 8'h1F;

  localparam SYSCONF   = 8'h20;
  localparam MEMCONF   = 8'h21;
  localparam HSINT     = 8'h22;
  localparam VSINTL    = 8'h23;
  localparam VSINTH    = 8'h24;
  localparam DMAWPD    = 8'h25;
  localparam DMALEN    = 8'h26;
  localparam DMACTRL   = 8'h27;
  localparam DMANUM    = 8'h28;
  localparam FDDVIRT   = 8'h29;
  localparam INTMASK   = 8'h2A;
  localparam CACHECONF = 8'h2B;
  localparam DMAWPA    = 8'h2D;

  localparam XSTAT     = 8'h00;
  localparam DMASTAT   = 8'h27;

`ifdef FDR
  localparam DMANUMH   = 8'h2C;
  localparam FRCTRL    = 8'h30;
  localparam FRCNT0    = 8'h30;
  localparam FRCNT1    = 8'h31;
  localparam FRCNT2    = 8'h32;
`endif

`ifdef FDR
  localparam FDR_VER = 1'b1;
`else
  localparam FDR_VER = 1'b0;
`endif

`ifdef IDE_VDAC
  localparam VDAC_VER = 3'h3;
`elsif IDE_VDAC2
  localparam VDAC_VER = 3'h7;
`else
  localparam VDAC_VER = 3'h0;
`endif

  localparam PORTFE = 8'hFE;
  localparam PORTFD = 8'hFD;
  localparam PORTXT = 8'hAF;
  localparam PORTF7 = 8'hF7;
  localparam COVOX  = 8'hFB;

`ifdef IDE_HDD
  localparam NIDE10 = 8'h10;
  localparam NIDE11 = 8'h11;
  localparam NIDE30 = 8'h30;
  localparam NIDE50 = 8'h50;
  localparam NIDE70 = 8'h70;
  localparam NIDE90 = 8'h90;
  localparam NIDEB0 = 8'hB0;
  localparam NIDED0 = 8'hD0;
  localparam NIDEF0 = 8'hF0;
  localparam NIDE08 = 8'h08;
  localparam NIDE28 = 8'h28;
  localparam NIDE48 = 8'h48;
  localparam NIDE68 = 8'h68;
  localparam NIDE88 = 8'h88;
  localparam NIDEA8 = 8'hA8;
  localparam NIDEC8 = 8'hC8;
  localparam NIDEE8 = 8'hE8;
`endif

  localparam VGCOM  = 8'h1F;
  localparam VGTRK  = 8'h3F;
  localparam VGSEC  = 8'h5F;
  localparam VGDAT  = 8'h7F;
  localparam VGSYS  = 8'hFF;

  localparam KJOY   = 8'h1F;
  localparam KMOUSE = 8'hDF;

  localparam SDCFG  = 8'h77;
  localparam SDDAT  = 8'h57;

  localparam COMPORT = 8'hEF;     // F8EF..FFEF - rs232 ports

  reg [3:0] spi_cs_n;
  reg pwr_up_reg;
  reg [7:0] rampage[0:3];
  wire gluclock_on;
  wire p7ffd_wr;

  assign sdcs_n = spi_cs_n[0];
  assign sd2cs_n = spi_cs_n[2];
`ifdef IDE_VDAC2
  assign ftcs_n = spi_cs_n[1];
`ifdef ESP32_SPI
  assign espcs_n = spi_cs_n[3];
`endif
`endif

  wire open_vg;
  wire [7:0] loa = a[7:0];
  wire [7:0] hoa = regs_we ? a[7:0] : a[15:8];

  wire vg_port = (loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT);
  wire vgsys_port = (loa==VGSYS);

  assign porthit = ((loa==PORTFE) || (loa==PORTXT) || (loa==PORTFD) || (loa==COVOX)) || ((loa==PORTF7) && !dos)
`ifdef IDE_HDD
  || ide_all
`endif
  || ((vg_port || vgsys_port) && (dos || open_vg)) || ((loa==KJOY) && !dos && !open_vg) || (loa==KMOUSE) || ((loa==SDCFG) || (loa==SDDAT)) || (loa==COMPORT);

`ifdef IDE_HDD
  wire ide_all = ide_even || ide_port11;
  wire ide_even = (loa[2:0] == 3'b000) && (loa[3] != loa[4]);      // even ports
    wire ide_port11 = (loa==NIDE11);                  // 11
    wire ide_port10 = (loa==NIDE10);                  // 10
    wire ide_portc8 = (loa==NIDEC8);                  // C8
`endif

  assign external_port = ((loa==PORTFD) && a[15])        // AY
                      || (((loa==VGCOM) || (loa==VGTRK) || (loa==VGSEC) || (loa==VGDAT)) && (dos || open_vg));

  assign dataout = porthit && iord && (~external_port);

  // zclk-synchronous strobes
  reg iowr_reg;
  reg iord_reg;
  reg port_wr;
  reg port_rd;

  always @(posedge zclk)
  begin
    iowr_reg <= iowr;
    iord_reg <= iord;

    if (!iowr_reg && iowr)
      port_wr <= 1'b1;
    else
      port_wr <= 1'b0;

    if (!iord_reg && iord)
      port_rd <= 1'b1;
    else
      port_rd <= 1'b0;
  end

  // reading ports
  always @*
  begin
    case (loa)
    PORTFE:
      dout = {1'b1, tape_read, 1'b1, keys_in};

`ifdef IDE_HDD
    NIDE10,NIDE30,NIDE50,NIDE70,NIDE90,NIDEB0,NIDED0,NIDEF0,NIDE08,NIDE28,NIDE48,NIDE68,NIDE88,NIDEA8,NIDEC8,NIDEE8:
      dout = iderdeven;
    NIDE11:
      dout = iderdodd;
`endif

      PORTXT:
      begin
        case (hoa)
        XSTAT:
          dout = {1'b0, pwr_up_reg, FDR_VER, 2'b0, VDAC_VER};

        DMASTAT:
          dout = {dma_act, 7'b0};

        RAMPAGE + 8'd2, RAMPAGE + 8'd3:
          dout = rampage[hoa[1:0]];

`ifdef FDR
          FRCNT0:
            dout = fdr_cnt[7:0];

          FRCNT1:
            dout = fdr_cnt[15:8];

          FRCNT2:
            dout = {5'b0, fdr_cnt[18:16]};
`endif
          default:
            dout = 8'hFF;

        endcase
      end

    VGSYS:
      dout = {vg_intrq, vg_drq, 6'b111111};

    KJOY:
`ifdef KEMPSTON_8BIT
      dout = kj_in;
`else
      dout = {3'b000, kj_in};
`endif

    KMOUSE:
      dout = mus_in;

    SDCFG:
      dout = 8'h00; // always SD inserted, SD is in R/W mode
    SDDAT:
      dout = sd_dataout;

    PORTF7:
    begin
      if (!a[14] && (a[8] ^ dos) && gluclock_on) // $BFF7 - data i/o
        dout = wait_read;
        // dout = 8'h55;
      else // any other $xxF7 port
        dout = 8'hFF;
    end

    COMPORT:
    begin
      dout = wait_read; // $F8EF..$FFEF
    end

    default:
      dout = 8'hFF;
    endcase
  end

  // power-up
  // This bit is loaded as 1 while FPGA is configured and automatically reset to 0 after STATUS port reading
  reg pwr_up = 1'b1;
  always @(posedge clk)
    if (iord_s & (loa == PORTXT) & (hoa == XSTAT))
    begin
      pwr_up_reg <= pwr_up;
      pwr_up <= 1'b0;
    end

  wire portfe_wr = (loa==PORTFE) && iowr_s;
  assign beeper_wr = portfe_wr;
  assign covox_wr = (loa==COVOX) && iowr_s;
  wire portxt_wr = ((loa==PORTXT) && iowr_s) || regs_we;
  wire portxt_rd = (loa==PORTXT) && iord_s;

  assign xt_page = {rampage[3], rampage[2], rampage[1], rampage[0]};

  // writing ports
  assign dmaport_wr[0] = portxt_wr && (hoa == DMASADDRL);
  assign dmaport_wr[1] = portxt_wr && (hoa == DMASADDRH);
  assign dmaport_wr[2] = portxt_wr && (hoa == DMASADDRX);
  assign dmaport_wr[3] = portxt_wr && (hoa == DMADADDRL);
  assign dmaport_wr[4] = portxt_wr && (hoa == DMADADDRH);
  assign dmaport_wr[5] = portxt_wr && (hoa == DMADADDRX);
  assign dmaport_wr[6] = portxt_wr && (hoa == DMALEN);
  assign dmaport_wr[7] = portxt_wr && (hoa == DMACTRL);
  assign dmaport_wr[8] = portxt_wr && (hoa == DMANUM);
`ifdef FDR
  assign dmaport_wr[9] = portxt_wr && (hoa == DMANUMH);
`endif

  assign zborder_wr    = portfe_wr;
  assign border_wr     = (portxt_wr && (hoa == XBORDER));
  assign zvpage_wr     = p7ffd_wr;
  assign vpage_wr      = (portxt_wr && (hoa == VPAGE ));
  assign vconf_wr      = (portxt_wr && (hoa == VCONF ));
  assign gx_offsl_wr   = (portxt_wr && (hoa == GXOFFSL));
  assign gx_offsh_wr   = (portxt_wr && (hoa == GXOFFSH));
  assign gy_offsl_wr   = (portxt_wr && (hoa == GYOFFSL));
  assign gy_offsh_wr   = (portxt_wr && (hoa == GYOFFSH));
  assign t0x_offsl_wr  = (portxt_wr && (hoa == T0XOFFSL));
  assign t0x_offsh_wr  = (portxt_wr && (hoa == T0XOFFSH));
  assign t0y_offsl_wr  = (portxt_wr && (hoa == T0YOFFSL));
  assign t0y_offsh_wr  = (portxt_wr && (hoa == T0YOFFSH));
  assign t1x_offsl_wr  = (portxt_wr && (hoa == T1XOFFSL));
  assign t1x_offsh_wr  = (portxt_wr && (hoa == T1XOFFSH));
  assign t1y_offsl_wr  = (portxt_wr && (hoa == T1YOFFSL));
  assign t1y_offsh_wr  = (portxt_wr && (hoa == T1YOFFSH));
  assign tsconf_wr     = (portxt_wr && (hoa == TSCONF));
  assign palsel_wr     = (portxt_wr && (hoa == PALSEL));
  assign tmpage_wr     = (portxt_wr && (hoa == TMPAGE));
  assign t0gpage_wr    = (portxt_wr && (hoa == T0GPAGE));
  assign t1gpage_wr    = (portxt_wr && (hoa == T1GPAGE));
  assign sgpage_wr     = (portxt_wr && (hoa == SGPAGE));
  assign hint_beg_wr   = (portxt_wr && (hoa == HSINT ));
  assign vint_begl_wr  = (portxt_wr && (hoa == VSINTL));
  assign vint_begh_wr  = (portxt_wr && (hoa == VSINTH));
`ifdef FDR
  assign fdr_cnt_lat   = (portxt_rd && (hoa == FRCNT0));
`endif

  reg m1_lock128;

  wire lock128_2 = memconf[7:6] == 2'b10;     // mode 2
  wire lock128_3 = memconf[7:6] == 2'b11;     // mode 3
  wire lock128 = lock128_3 ? 1'b0 : (lock128_2 ? m1_lock128 : memconf[6]);

  always @(posedge clk) if (opfetch)
    m1_lock128 <= !(din[7] ^ din[6]);

  always @(posedge clk or posedge rst)
    if (rst)
    begin
      fmaddr[4] <= 1'b0;
      intmask <= 8'b1;
      fddvirt <= 8'b0;
      sysconf <= 8'h00;       // 3.5 MHz
      memconf <= 8'h04;       // no map
      cacheconf <= 4'h0;      // no cache

      rampage[0] <= 8'h00;
      rampage[1] <= 8'h05;
      rampage[2] <= 8'h02;
      rampage[3] <= 8'h00;

`ifdef FDR
      fdr_en <= 1'b0;
`endif
    end
    else  // if (rst)
    begin
      if (p7ffd_wr)
      begin
          memconf[0] <= din[4];
          rampage[3] <= {2'b0, lock128_3 ? {din[5], din[7:6]} : ({1'b0, lock128 ? 2'b0 : din[7:6]}), din[2:0]};
      end
      
      else if (portxt_wr)
      begin
        if (hoa[7:2] == RAMPAGE[7:2])
          rampage[hoa[1:0]] <= din;
      
        if (hoa == FMADDR)
          fmaddr <= din[4:0];
      
        if (hoa == SYSCONF)
        begin
          sysconf <= din;
            cacheconf <= {4{din[2]}};
        end
      
        if (hoa == DMAWPD)
          dmawpdev <= din[1:0];
      
        if (hoa == CACHECONF)
          cacheconf <= din[3:0];
      
        if (hoa == MEMCONF)
          memconf <= din;
      
        if (hoa == FDDVIRT)
          fddvirt <= din;
      
`ifdef FDR
        if (hoa == FRCTRL)
          fdr_en <= din[0];
`endif
      
        if (hoa == INTMASK)
          intmask <= din;
      end
    end

  // 7FFD port
  reg lock48;

  assign p7ffd_wr = !a[15] && (loa==PORTFD) && iowr_s && !lock48;

  always @(posedge clk or posedge rst)
    if (rst)
      lock48 <= 1'b0;
    else if (p7ffd_wr && !lock128_3)
      lock48 <= din[5];

  // AY control
  wire ay_hit = (loa==PORTFD) & a[15];
  assign ay_bc1  = ay_hit & a[14] & iordwr;
  assign ay_bdir = ay_hit & iowr;

  // VG93
  reg [1:0] drive_sel_raw;

  wire [3:0] fddvrt = fddvirt[3:0];
  wire virt_vg = fddvrt[drive_sel_raw];
  assign open_vg = fddvirt[7];
  assign drive_sel = {drive_sel_raw[1], drive_sel_raw[0] ^ cfg_floppy_swap};

  wire vg_wen = (dos || open_vg) && !vdos && !virt_vg;
  assign vg_cs_n = !(iordwr && vg_port && vg_wen);
  assign vg_wrFF = iowr_s && vgsys_port && vg_wen;
  wire vg_wrDS = iowr_s && vgsys_port && (dos || open_vg);

  assign vdos_on  = iordwr_s && (vg_port || vgsys_port) && dos && !vdos && virt_vg;
  assign vdos_off = iordwr_s && vg_port && vdos;

  // write drive number
  always @(posedge clk)
    if (vg_wrDS)
      drive_sel_raw <= din;

  // SD card (Z-controller compatible)
  wire sdcfg_wr;
  wire sddat_wr;
  wire sddat_rd;

  assign sdcfg_wr = (loa==SDCFG) && iowr_s;
  assign sddat_wr = (loa==SDDAT) && iowr_s;
  assign sddat_rd = (loa==SDDAT) && iord_s;

  // SDCFG write - sdcs_n control
  always @(posedge clk or posedge rst)
    if (rst)
    begin
      spi_cs_n <= 4'b1111;
      spi_mode <= 1'b0;
    end
    else if (sdcfg_wr)
    begin
      spi_cs_n <= {~din[4:2], din[1]};
      // spi_mode <= din[7];
    end

  // start signal for SPI module with resyncing to fclk
  assign sd_start = sddat_wr || sddat_rd;

  // data for SPI module
  assign sd_datain = wr ? din : 8'hFF;

  // xxF7
  wire portf7_wr = ((loa==PORTF7) && (a[8]==1'b1) && port_wr && (!dos || vdos));
  wire portf7_rd = ((loa==PORTF7) && (a[8]==1'b1) && port_rd && (!dos || vdos));

  // EFF7 port
  reg [7:0] peff7;
  always @(posedge clk  or posedge rst)
    if (rst)
      peff7 <= 8'h00;
    else if (!a[12] && portf7_wr && !dos)   // #EEF7 in dos is not accessible
      peff7 <= din;

  // gluclock ports
  assign gluclock_on = peff7[7] || dos;        // in dos mode EEF7 is not accessible, gluclock access is ON in dos mode.

  // comports
  wire comport_wr   = ((loa == COMPORT) && port_wr);
  wire comport_rd   = ((loa == COMPORT) && port_rd);

  // write to wait registers
  always @(posedge zclk)
  begin
    // gluclocks
    if (gluclock_on && portf7_wr)
    begin
      if (!a[14]) // $BFF7 - data reg
        wait_write <= din;

      if (!a[13]) // $DFF7 - addr reg
        wait_addr <= din;
    end

    // com ports
    if (comport_wr) // $xxEF
      wait_write <= din;

    if (comport_wr || comport_rd)
      wait_addr <= a[15:8];

    if ((loa==PORTXT) && (hoa == DMAWPA))
      wait_addr <= din;
  end

  // wait from wait registers
  assign wait_start_gluclock = (gluclock_on && !a[14] && (portf7_rd || portf7_wr)); // $BFF7 - gluclock r/w
  assign wait_start_comport = (comport_rd || comport_wr);

`ifdef IDE_HDD
  // IDE ports
  // do NOT generate IDE write, if neither of ide_wrhi|lo latches set and writing to NIDE10
  wire ide_cs0 = ide_even && !ide_portc8;
  wire ide_cs1 = ide_portc8;
  wire ide_rd = rd && !(ide_rd_latch && ide_port10);
  wire ide_wr = wr && !(!ide_wrlo_latch && !ide_wrhi_latch && ide_port10);
  assign ide_req = iorq_s && ide_even && (ide_rd || ide_wr);
  assign ide_cs0_n = !ide_cs0;
  assign ide_cs1_n = !ide_cs1;

  always @(posedge clk)
    if (ide_req)
      ide_stall <= 1'b1;
    else if (ide_ready)
      ide_stall <= 1'b0;

  // control read & write triggers, which allow nemo-divide mod to work.
  // read trigger:
  reg ide_rd_trig;  // nemo-divide read trigger
  always @(posedge zclk)
  begin
    if (ide_port10 && port_rd && !ide_rd_trig)
      ide_rd_trig <= 1'b1;
    else if (ide_all && (port_rd || port_wr))
      ide_rd_trig <= 1'b0;
  end

  // two triggers for write sequence
  reg ide_wrlo_trig,  ide_wrhi_trig;  // nemo-divide write triggers
  always @(posedge zclk)
  if (ide_all && (port_rd || port_wr))
  begin
    if (ide_port11 && port_wr)
      ide_wrhi_trig <= 1'b1;
    else
      ide_wrhi_trig <= 1'b0;

    if (ide_port10 && port_wr && !ide_wrhi_trig && !ide_wrlo_trig)
      ide_wrlo_trig <= 1'b1;
    else
      ide_wrlo_trig <= 1'b0;
  end

  // normal read: #10(low), #11(high)
  // divide read: #10(low), #10(high)
  //
  // normal write: #11(high), #10(low)
  // divide write: #10(low),  #10(high)

  reg [15:0] idewrreg; // write register, either low or high part is pre-written here,
                        // while other part is out directly from Z80 bus
  always @(posedge zclk)
  begin
    if (port_wr && ide_port11)
      idewrreg[15:8] <= din;

    if (port_wr && ide_port10 && !ide_wrlo_trig)
      idewrreg[ 7:0] <= din;
  end

  // generate read cycles for IDE as usual, except for reading #10
  // instead of #11 for high byte (nemo-divide). I use additional latch
  // since 'ide_rd_trig' clears during second Z80 IO read cycle to #10
  reg ide_rd_latch; // to save state of trigger during read cycle
  always @*
    if (!rd)
      ide_rd_latch <= ide_rd_trig;

  reg ide_wrlo_latch, ide_wrhi_latch; // save state during write cycles
  always @*
    if (!wr)
    begin
      ide_wrlo_latch <= ide_wrlo_trig; // same for write triggers
      ide_wrhi_latch <= ide_wrhi_trig;
    end

  // data read by Z80 from IDE
  wire idein_lo_rd  = port_rd && ide_port10 && (!ide_rd_trig);                      // while high part is remembered here
  wire [7:0] iderdodd = iderdreg[15:8];                                               // read data from "odd" port (#11)
  wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? iderdreg[15:8] : iderdreg[7:0];  // to control read data from "even" ide ports (all except #11)
  // wire [7:0] iderdeven = (ide_rd_latch && ide_port10) ? idehiin[7:0] : ide_in[7:0];  // to control read data from "even" ide ports (all except #11)

  reg [15:0] iderdreg;
  // reg [7:0] idehiin;                  // IDE high part read register: low part is read directly to Z80 bus,
  always @(posedge clk)
    if (ide_stb)
      iderdreg <= ide_in;
    // if (idein_lo_rd)
      // idehiin <= ide_in[15:8];

  // data written to IDE from Z80
  wire [7:0] ideout1 = ide_wrhi_latch ? idewrreg[15:8] : din[ 7:0];
  wire [7:0] ideout0 = ide_wrlo_latch ? idewrreg[ 7:0] : din[ 7:0];
  assign ide_out = {ideout1, ideout0};
`endif

endmodule
