Subversion Repositories pentevo

Rev

Rev 340 | Rev 395 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. // PentEvo project (c) NedoPC 2008-2010
  2. //
  3. // most of pentevo ports are here
  4.  
  5. `include "../include/tune.v"
  6.  
  7. module zports(
  8.  
  9.         input  wire        zclk,   // z80 clock
  10.         input  wire        fclk,  // global FPGA clock
  11.         input  wire        rst_n, // system reset
  12.  
  13.         input  wire        zpos,
  14.         input  wire        zneg,
  15.  
  16.  
  17.         input  wire [ 7:0] din,
  18.         output reg  [ 7:0] dout,
  19.         output wire        dataout,
  20.         input  wire [15:0] a,
  21.  
  22.         input  wire        iorq_n,
  23.         input  wire        mreq_n,
  24.         input  wire        m1_n,
  25.         input  wire        rd_n,
  26.         input  wire        wr_n,
  27.  
  28.         output reg         porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
  29.  
  30.         output wire [15:0] ideout,
  31.         input  wire [15:0] idein,
  32.         output wire        idedataout, // IDE must IN data from IDE device when idedataout=0, else it OUTs
  33.         output wire [ 2:0] ide_a,
  34.         output wire        ide_cs0_n,
  35.         output wire        ide_cs1_n,
  36.         output wire        ide_rd_n,
  37.         output wire        ide_wr_n,
  38.  
  39.  
  40.         input  wire [ 4:0] keys_in, // keys (port FE)
  41.         input  wire [ 7:0] mus_in,  // mouse (xxDF)
  42.         input  wire [ 4:0] kj_in,
  43.  
  44.         output reg  [ 3:0] border,
  45.  
  46.  
  47.         input  wire        dos,
  48.  
  49.  
  50.         output wire        ay_bdir,
  51.         output wire        ay_bc1,
  52.  
  53.         output wire [ 7:0] p7ffd,
  54.         output wire [ 7:0] peff7,
  55.  
  56.         input  wire [ 1:0] rstrom,
  57.  
  58.         input  wire        tape_read,
  59.  
  60.         output wire        vg_cs_n,
  61.         input  wire        vg_intrq,
  62.         input  wire        vg_drq, // from vg93 module - drq + irq read
  63.         output wire        vg_wrFF,        // write strobe of #FF port
  64.  
  65.         output reg         sdcs_n,
  66.         output wire        sd_start,
  67.         output wire [ 7:0] sd_datain,
  68.         input  wire [ 7:0] sd_dataout,
  69.  
  70.         // WAIT-ports related
  71.         //
  72.         output reg  [ 7:0] gluclock_addr,
  73.         //
  74.         output reg  [ 2:0] comport_addr,
  75.         //
  76.         output wire        wait_start_gluclock, // begin wait from some ports
  77.         output wire        wait_start_comport,  //
  78.         //
  79.         output reg         wait_rnw,   // whether it was read(=1) or write(=0)
  80.         output reg  [ 7:0] wait_write,
  81.         input  wire [ 7:0] wait_read,
  82.  
  83.  
  84.         output wire        atmF7_wr_fclk, // used in atm_pager.v
  85.  
  86.  
  87.         output reg  [ 2:0] atm_scr_mode, // RG0..RG2 in docs
  88.         output reg         atm_turbo,    // turbo mode ON
  89.         output reg         atm_pen,      // pager_off in atm_pager.v, NOT inverted!!!
  90.         output reg         atm_cpm_n,    // permanent dos on
  91.         output reg         atm_pen2,     // PEN2 - fucking palette mode, NOT inverted!!!
  92.  
  93.         output wire        romrw_en, // from port BF
  94.  
  95.  
  96.         output wire        pent1m_ram0_0, // d3.eff7
  97.         output wire        pent1m_1m_on,  // d2.eff7
  98.         output wire [ 5:0] pent1m_page,   // full 1 meg page number
  99.         output wire        pent1m_ROM,     // d4.7ffd
  100.  
  101.  
  102.         output wire        atm_palwr,   // palette write strobe
  103.         output wire [ 5:0] atm_paldata, // palette write data
  104.  
  105.         output wire        covox_wr,
  106.         output wire        beeper_wr
  107. );
  108.  
  109.  
  110.         reg rstsync1,rstsync2;
  111.  
  112.  
  113.         localparam PORTFE = 8'hFE;
  114.         localparam PORTF6 = 8'hF6;
  115.         localparam PORTF7 = 8'hF7;
  116.  
  117.         localparam NIDE10 = 8'h10;
  118.         localparam NIDE11 = 8'h11;
  119.         localparam NIDE30 = 8'h30;
  120.         localparam NIDE50 = 8'h50;
  121.         localparam NIDE70 = 8'h70;
  122.         localparam NIDE90 = 8'h90;
  123.         localparam NIDEB0 = 8'hB0;
  124.         localparam NIDED0 = 8'hD0;
  125.         localparam NIDEF0 = 8'hF0;
  126.         localparam NIDEC8 = 8'hC8;
  127.  
  128.         localparam PORTFD = 8'hFD;
  129.  
  130.         localparam VGCOM  = 8'h1F;
  131.         localparam VGTRK  = 8'h3F;
  132.         localparam VGSEC  = 8'h5F;
  133.         localparam VGDAT  = 8'h7F;
  134.         localparam VGSYS  = 8'hFF;
  135.  
  136.         localparam KJOY   = 8'h1F;
  137.         localparam KMOUSE = 8'hDF;
  138.  
  139.         localparam SDCFG  = 8'h77;
  140.         localparam SDDAT  = 8'h57;
  141.  
  142.         localparam ATMF7  = 8'hF7;
  143.         localparam ATM77  = 8'h77;
  144.  
  145.         localparam ZXEVBF = 8'hBF; // xxBF config port
  146.  
  147.         localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
  148.  
  149.  
  150.         localparam COVOX   = 8'hFB;
  151.  
  152.  
  153.  
  154.  
  155.         reg external_port;
  156.  
  157.         reg port_wr;
  158.         reg port_rd;
  159.  
  160.         reg iowr_reg;
  161.         reg iord_reg;
  162.  
  163.  
  164.         reg port_wr_fclk,
  165.             port_rd_fclk;
  166.  
  167.         reg [1:0] iowr_reg_fclk,
  168.                   iord_reg_fclk;
  169.  
  170.  
  171.         wire [7:0] loa;
  172.  
  173.         wire portfe_wr;
  174.  
  175.  
  176.  
  177.         wire ideout_hi_wr;
  178.         wire idein_lo_rd;
  179.         reg [7:0] idehiin; // IDE high part read register: low part is read directly to Z80 bus,
  180.                            // while high part is remembered here
  181.         reg ide_ports; // ide ports selected
  182.  
  183.         reg ide_rd_trig; // nemo-divide read trigger
  184.         reg ide_rd_latch; // to save state of trigger during read cycle
  185.  
  186.         reg ide_wrlo_trig,  ide_wrhi_trig;  // nemo-divide write triggers
  187.         reg ide_wrlo_latch, ide_wrhi_latch; // save state during write cycles
  188.  
  189.  
  190.  
  191.         reg  [15:0] idewrreg; // write register, either low or high part is pre-written here,
  192.                               // while other part is out directly from Z80 bus
  193.  
  194.         wire [ 7:0] iderdeven; // to control read data from "even" ide ports (all except #11)
  195.         wire [ 7:0] iderdodd;  // read data from "odd" port (#11)
  196.  
  197.  
  198.  
  199.         reg pre_bc1,pre_bdir;
  200.  
  201.         wire gluclock_on;
  202.  
  203.  
  204.  
  205.         reg  shadow_en_reg; //bit0.xxBF
  206.         reg   romrw_en_reg; //bit1.xxBF
  207.  
  208.         wire shadow;
  209.  
  210.  
  211.  
  212.  
  213.  
  214.         assign shadow = dos || shadow_en_reg;
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.         assign loa=a[7:0];
  222.  
  223.         always @*
  224.         begin
  225.                 if( (loa==PORTFE) || (loa==PORTF6) ||
  226.                     (loa==PORTFD) ||
  227.  
  228.                     (loa==NIDE10) || (loa==NIDE11) || (loa==NIDE30) || (loa==NIDE50) || (loa==NIDE70) ||
  229.                     (loa==NIDE90) || (loa==NIDEB0) || (loa==NIDED0) || (loa==NIDEF0) || (loa==NIDEC8) ||
  230.  
  231.                     (loa==KMOUSE) ||
  232.  
  233.                     ( (loa==VGCOM)&&shadow ) || ( (loa==VGTRK)&&shadow ) || ( (loa==VGSEC)&&shadow ) || ( (loa==VGDAT)&&shadow ) ||
  234.                     ( (loa==VGSYS)&&shadow ) || ( (loa==KJOY)&&(!shadow) ) ||
  235.  
  236.                     ( (loa==PORTF7)&&(!shadow) ) || ( (loa==SDCFG)&&(!shadow) ) || ( (loa==SDDAT) ) ||
  237.  
  238.                     ( (loa==ATMF7)&&shadow ) || ( (loa==ATM77)&&shadow ) ||
  239.  
  240.                     ( loa==ZXEVBF ) || ( loa==COMPORT )
  241.                   )
  242.  
  243.  
  244.  
  245.                         porthit = 1'b1;
  246.                 else
  247.                         porthit = 1'b0;
  248.         end
  249.  
  250.         always @*
  251.         begin
  252.                 if( ((loa==PORTFD) && (a[15:14]==2'b11)) || // 0xFFFD ports
  253.                     (( (loa==VGCOM)&&shadow ) || ( (loa==VGTRK)&&shadow ) || ( (loa==VGSEC)&&shadow ) || ( (loa==VGDAT)&&shadow )) ) // vg93 ports
  254.                         external_port = 1'b1;
  255.                 else
  256.                         external_port = 1'b0;
  257.         end
  258.  
  259.         assign dataout = porthit & (~iorq_n) & (~rd_n) & (~external_port);
  260.  
  261.  
  262.  
  263.         // this is zclk-synchronous strobes
  264.         always @(posedge zclk)
  265.         begin
  266.                 iowr_reg <= ~(iorq_n | wr_n);
  267.                 iord_reg <= ~(iorq_n | rd_n);
  268.  
  269.                 if( (!iowr_reg) && (!iorq_n) && (!wr_n) )
  270.                         port_wr <= 1'b1;
  271.                 else
  272.                         port_wr <= 1'b0;
  273.  
  274.  
  275.                 if( (!iord_reg) && (!iorq_n) && (!rd_n) )
  276.                         port_rd <= 1'b1;
  277.                 else
  278.                         port_rd <= 1'b0;
  279.         end
  280.  
  281.  
  282.  
  283.  
  284.         // fclk-synchronous stobes
  285.         //
  286.         always @(posedge fclk) if( zpos )
  287.         begin
  288.                 iowr_reg_fclk[0] <= ~(iorq_n | wr_n);
  289.                 iord_reg_fclk[0] <= ~(iorq_n | rd_n);
  290.         end
  291.  
  292.         always @(posedge fclk)
  293.         begin
  294.                 iowr_reg_fclk[1] <= iowr_reg_fclk[0];
  295.                 iord_reg_fclk[1] <= iord_reg_fclk[0];
  296.         end
  297.  
  298.         always @(posedge fclk)
  299.         begin
  300.                 port_wr_fclk <= iowr_reg_fclk[0] && (!iowr_reg_fclk[1]);
  301.                 port_rd_fclk <= iord_reg_fclk[0] && (!iord_reg_fclk[1]);
  302.         end
  303.  
  304.  
  305.  
  306.  
  307.  
  308.         // dout data
  309.         always @*
  310.         begin
  311.                 case( loa )
  312.                 PORTFE:
  313.                         dout = { 1'b1, tape_read, 1'b0, keys_in };
  314.                 PORTF6:
  315.                         dout = { 1'b1, tape_read, 1'b0, keys_in };
  316.  
  317.  
  318.                 NIDE10,NIDE30,NIDE50,NIDE70,NIDE90,NIDEB0,NIDED0,NIDEF0,NIDEC8:
  319.                         dout = iderdeven;
  320.                 NIDE11:
  321.                         dout = iderdodd;
  322.  
  323.  
  324.                 //PORTFD:
  325.  
  326.                 VGSYS:
  327.                         dout = { vg_intrq, vg_drq, 6'b111111 };
  328.  
  329.                 KJOY:
  330.                         dout = {3'b000, kj_in};
  331.                 KMOUSE:
  332.                         dout = mus_in;
  333.  
  334.                 SDCFG:
  335.                         dout = 8'h00; // always SD inserted, SD is in R/W mode
  336.                 SDDAT:
  337.                         dout = sd_dataout;
  338.  
  339.  
  340.                 PORTF7: begin
  341.                         if( !a[14] && (a[8]^shadow) && gluclock_on ) // $BFF7 - data i/o
  342.                                 dout = wait_read;
  343.                         else // any other $xxF7 port
  344.                                 dout = 8'hFF;
  345.                 end
  346.  
  347.                 COMPORT: begin
  348.                         dout = wait_read; // $F8EF..$FFEF
  349.                 end
  350.  
  351.  
  352.  
  353.                 default:
  354.                         dout = 8'hFF;
  355.                 endcase
  356.         end
  357.  
  358.  
  359.  
  360.         assign portfe_wr    = (((loa==PORTFE) || (loa==PORTF6)) && port_wr);
  361.         assign portfd_wr    = ( (loa==PORTFD) && port_wr);
  362.  
  363.         // F7 ports (like EFF7) are accessible in shadow mode but at addresses like EEF7, DEF7, BEF7 so that
  364.         // there are no conflicts in shadow mode with ATM xFF7 and x7F7 ports
  365.         assign portf7_wr    = ( (loa==PORTF7) && (a[8]==1'b1) && port_wr && (!shadow) ) ||
  366.                               ( (loa==PORTF7) && (a[8]==1'b0) && port_wr &&   shadow  ) ;
  367.  
  368.         assign portf7_rd    = ( (loa==PORTF7) && (a[8]==1'b1) && port_rd && (!shadow) ) ||
  369.                               ( (loa==PORTF7) && (a[8]==1'b0) && port_rd &&   shadow  ) ;
  370.  
  371.         assign vg_wrFF = ( ( (loa==VGSYS)&&shadow ) && port_wr);
  372.  
  373.         assign comport_wr   = ( (loa==COMPORT) && port_wr);
  374.         assign comport_rd   = ( (loa==COMPORT) && port_rd);
  375.  
  376.  
  377.  
  378.         //border port FE
  379.         wire portwe_wr_fclk;
  380.  
  381.         assign portfe_wr_fclk = (((loa==PORTFE) || (loa==PORTF6)) && port_wr_fclk);
  382.  
  383.         always @(posedge fclk)
  384.         if( portfe_wr_fclk )
  385.                 border <= { ~a[3], din[2:0] };
  386.  
  387.  
  388.  
  389.  
  390.  
  391.  
  392.         // IDE ports
  393.  
  394.         // IDE physical ports (that go to IDE device)
  395.         always @(loa)
  396.                 case( loa )
  397.                 NIDE10,NIDE30,NIDE50,NIDE70,NIDE90,NIDEB0,NIDED0,NIDEF0,NIDEC8: ide_ports = 1'b1;
  398.                 default: ide_ports = 1'b0;
  399.                 endcase
  400.  
  401.  
  402.         assign idein_lo_rd  = port_rd && (loa==NIDE10) && (!ide_rd_trig);
  403.  
  404.         // control read & write triggers, which allow nemo-divide mod to work.
  405.         //
  406.         // read trigger:
  407.         always @(posedge zclk)
  408.         begin
  409.                 if( (loa==NIDE10) && port_rd && !ide_rd_trig )
  410.                         ide_rd_trig <= 1'b1;
  411.                 else if( ( ide_ports || (loa==NIDE11) ) && ( port_rd || port_wr ) )
  412.                         ide_rd_trig <= 1'b0;
  413.         end
  414.         //
  415.         // two triggers for write sequence...
  416.         always @(posedge zclk)
  417.         if( ( ide_ports || (loa==NIDE11) ) && ( port_rd || port_wr ) )
  418.         begin
  419.                 if( (loa==NIDE11) && port_wr )
  420.                         ide_wrhi_trig <= 1'b1;
  421.                 else
  422.                         ide_wrhi_trig <= 1'b0;
  423.                 //
  424.                 if( (loa==NIDE10) && port_wr && !ide_wrhi_trig && !ide_wrlo_trig )
  425.                         ide_wrlo_trig <= 1'b1;
  426.                 else
  427.                         ide_wrlo_trig <= 1'b0;
  428.         end
  429.  
  430.         // normal read: #10(low), #11(high)
  431.         // divide read: #10(low), #10(high)
  432.         //
  433.         // normal write: #11(high), #10(low)
  434.         // divide write: #10(low),  #10(high)
  435.  
  436.  
  437.         always @(posedge zclk)
  438.         begin
  439.                 if( port_wr && (loa==NIDE11) )
  440.                         idewrreg[15:8] <= din;
  441.  
  442.                 if( port_wr && (loa==NIDE10) && !ide_wrlo_trig )
  443.                         idewrreg[ 7:0] <= din;
  444.         end
  445.  
  446.  
  447.  
  448.  
  449.         always @(posedge zclk)
  450.         if( idein_lo_rd )
  451.                         idehiin <= idein[15:8];
  452.  
  453.  
  454.         assign ide_a = a[7:5];
  455.  
  456.  
  457.         // This is unknown shit... Probably need more testing with old WD
  458.         // drives WITHOUT this commented fix.
  459.         //
  460.         // trying to fix old WD drives...
  461.         //assign ide_cs0_n = iorq_n | (rd_n&wr_n) | (~ide_ports) | (~(loa!=NIDEC8));
  462.         //assign ide_cs1_n = iorq_n | (rd_n&wr_n) | (~ide_ports) | (~(loa==NIDEC8));
  463.         // fix ends...
  464.  
  465.  
  466.         assign ide_cs0_n = (~ide_ports) | (~(loa!=NIDEC8));
  467.         assign ide_cs1_n = (~ide_ports) | (~(loa==NIDEC8));
  468.  
  469.  
  470.         // generate read cycles for IDE as usual, except for reading #10
  471.         // instead of #11 for high byte (nemo-divide). I use additional latch
  472.         // since 'ide_rd_trig' clears during second Z80 IO read cycle to #10
  473.         always @* if( rd_n ) ide_rd_latch <= ide_rd_trig;
  474.         //
  475.         assign ide_rd_n = iorq_n | rd_n | (~ide_ports) | (ide_rd_latch && (loa==NIDE10));
  476.  
  477.         always @* if( wr_n ) ide_wrlo_latch <= ide_wrlo_trig; // same for write triggers
  478.         always @* if( wr_n ) ide_wrhi_latch <= ide_wrhi_trig; //
  479.         //
  480.         assign ide_wr_n = iorq_n | wr_n | (~ide_ports) | ( (loa==NIDE10) && !ide_wrlo_latch && !ide_wrhi_latch );
  481.                                                   // do NOT generate IDE write, if neither of ide_wrhi|lo latches
  482.                                                   // set and writing to NIDE10
  483.  
  484.  
  485.  
  486.         assign idedataout = ide_rd_n;
  487.  
  488.  
  489.  
  490.         // data read by Z80 from IDE
  491.         //
  492.         assign iderdodd[ 7:0] = idehiin[ 7:0];
  493.         //
  494.         assign iderdeven[ 7:0] = (ide_rd_latch && (loa==NIDE10)) ? idehiin[ 7:0] : idein[ 7:0];
  495.  
  496.         // data written to IDE from Z80
  497.         //
  498.         assign ideout[15:8] = ide_wrhi_latch ? idewrreg[15:8] : din[ 7:0];
  499.         assign ideout[ 7:0] = ide_wrlo_latch ? idewrreg[ 7:0] : din[ 7:0];
  500.  
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.         // AY control
  508.         always @*
  509.         begin
  510.                 pre_bc1 = 1'b0;
  511.                 pre_bdir = 1'b0;
  512.  
  513.                 if( loa==PORTFD )
  514.                 begin
  515.                         if( a[15:14]==2'b11 )
  516.                         begin
  517.                                 pre_bc1=1'b1;
  518.                                 pre_bdir=1'b1;
  519.                         end
  520.                         else if( a[15:14]==2'b10 )
  521.                         begin
  522.                                 pre_bc1=1'b0;
  523.                                 pre_bdir=1'b1;
  524.                         end
  525.                 end
  526.         end
  527.  
  528.         assign ay_bc1  = pre_bc1  & (~iorq_n) & ((~rd_n)|(~wr_n));
  529.         assign ay_bdir = pre_bdir & (~iorq_n) & (~wr_n);
  530.  
  531.  
  532.  
  533.         // 7FFD port
  534.         reg [7:0] p7ffd_int,peff7_int;
  535.         reg p7ffd_rom_int;
  536.         wire block7ffd;
  537.         wire block1m;
  538.  
  539.         always @(posedge zclk, negedge rst_n)
  540.         begin
  541.                 if( !rst_n )
  542.                         p7ffd_int <= 7'h00;
  543.                 else if( (a[15]==1'b0) && portfd_wr && (!block7ffd) )
  544.                         p7ffd_int <= din; // 2..0 - page, 3 - screen, 4 - rom, 5 - block48k, 6..7 -
  545.         end
  546.  
  547.         always @(posedge zclk)
  548.         begin
  549.                 if( rstsync2 )
  550.                         p7ffd_rom_int <= rstrom[0];
  551.                 else if( (a[15]==1'b0) && portfd_wr && (!block7ffd) )
  552.                         p7ffd_rom_int <= din[4];
  553.         end
  554.  
  555.         assign block7ffd=p7ffd_int[5] & block1m;
  556.  
  557.  
  558.         // EFF7 port
  559.         always @(posedge zclk, negedge rst_n)
  560.         begin
  561.                 if( !rst_n )
  562.                         peff7_int <= 8'h00;
  563.                 else if( !a[12] && portf7_wr && (!shadow) ) // EEF7 in shadow mode is abandoned!
  564.                         peff7_int <= din; // 4 - turbooff, 0 - p16c on, 2 - block1meg
  565.         end
  566.         assign block1m = peff7_int[2];
  567.  
  568.         assign p7ffd = { (block1m ? 3'b0 : p7ffd_int[7:5]),p7ffd_rom_int,p7ffd_int[3:0]};
  569.  
  570.         assign peff7 = block1m ? { peff7_int[7], 1'b0, peff7_int[5], peff7_int[4], 3'b000, peff7_int[0] } : peff7_int;
  571.  
  572.  
  573.         assign pent1m_ROM       = p7ffd_int[4];
  574.         assign pent1m_page[5:0] = { p7ffd_int[7:5], p7ffd_int[2:0] };
  575.         assign pent1m_1m_on     = ~peff7_int[2];
  576.         assign pent1m_ram0_0    = peff7_int[3];
  577.  
  578.  
  579.  
  580.  
  581.         // gluclock ports (bit7:eff7 is above)
  582.  
  583.         assign gluclock_on = peff7_int[7] || shadow; // in shadow mode EEF7 is abandoned: instead, gluclock access
  584.                                                      // is ON forever in shadow mode.
  585.  
  586.         always @(posedge zclk)
  587.         begin
  588.                 if( gluclock_on && portf7_wr ) // gluclocks on
  589.                 begin
  590.                         if( !a[13] ) // $DFF7 - addr reg
  591.                                 gluclock_addr <= din;
  592.  
  593.                         // write to waiting register is not here - in separate section managing wait_write
  594.                 end
  595.         end
  596.  
  597.  
  598.         // comports
  599.  
  600.         always @(posedge zclk)
  601.         begin
  602.                 if( comport_wr || comport_rd )
  603.                         comport_addr <= a[10:8 ];
  604.         end
  605.  
  606.  
  607.  
  608.         // write to wait registers
  609.         always @(posedge zclk)
  610.         begin
  611.                 // gluclocks
  612.                 if( gluclock_on && portf7_wr && !a[14] ) // $BFF7 - data reg
  613.                         wait_write <= din;
  614.                 // com ports
  615.                 else if( comport_wr ) // $F8EF..$FFEF - comports
  616.                         wait_write <= din;
  617.         end
  618.  
  619.         // wait from wait registers
  620.         //
  621.         // ACHTUNG!!!! here portxx_wr are ON Z80 CLOCK! logic must change when moving to fclk strobes
  622.         //
  623.         assign wait_start_gluclock = ( gluclock_on && !a[14] && (portf7_rd || portf7_wr) ); // $BFF7 - gluclock r/w
  624.         //
  625.         assign wait_start_comport = ( comport_rd || comport_wr );
  626.         //
  627.         //
  628.         always @(posedge zclk) // wait rnw - only meanful during wait
  629.         begin
  630.                 if( port_wr )
  631.                         wait_rnw <= 1'b0;
  632.  
  633.                 if( port_rd )
  634.                         wait_rnw <= 1'b1;
  635.         end
  636.  
  637.  
  638.  
  639.  
  640.  
  641.         // VG93 control
  642.         assign vg_cs_n =  (~shadow) | iorq_n | (rd_n & wr_n) | ( ~((loa==VGCOM)|(loa==VGTRK)|(loa==VGSEC)|(loa==VGDAT)) );
  643.  
  644.  
  645.  
  646.  
  647.  
  648. // reset rom selection
  649.  
  650.         always @(posedge zclk)
  651.         begin
  652.                 rstsync1<=~rst_n;
  653.                 rstsync2<=rstsync1;
  654.         end
  655.  
  656.  
  657.  
  658.  
  659. // SD card (z-controlâ••r compatible)
  660.  
  661.         wire sdcfg_wr,sddat_wr,sddat_rd;
  662.  
  663.         assign sdcfg_wr = ( (loa==SDCFG) && port_wr && (!shadow) )                  ||
  664.                           ( (loa==SDDAT) && port_wr &&   shadow  && (a[15]==1'b1) ) ;
  665.  
  666.         assign sddat_wr = ( (loa==SDDAT) && port_wr && (!shadow) )                  ||
  667.                           ( (loa==SDDAT) && port_wr &&   shadow  && (a[15]==1'b0) ) ;
  668.  
  669.         assign sddat_rd = ( (loa==SDDAT) && port_rd              );
  670.  
  671.         // SDCFG write - sdcs_n control
  672.         always @(posedge zclk, negedge rst_n)
  673.         begin
  674.                 if( !rst_n )
  675.                         sdcs_n <= 1'b1;
  676.                 else // posedge zclk
  677.                         if( sdcfg_wr )
  678.                                 sdcs_n <= din[1];
  679.         end
  680.  
  681.  
  682.         // start signal for SPI module with resyncing to fclk
  683.  
  684.         reg sd_start_toggle;
  685.         reg [2:0] sd_stgl;
  686.  
  687.         // Z80 clock
  688.         always @(posedge zclk)
  689.                 if( sddat_wr || sddat_rd )
  690.                         sd_start_toggle <= ~sd_start_toggle;
  691.  
  692.         // FPGA clock
  693.         always @(posedge fclk)
  694.                 sd_stgl[2:0] <= { sd_stgl[1:0], sd_start_toggle };
  695.  
  696.         assign sd_start = ( sd_stgl[1] != sd_stgl[2] );
  697.  
  698.  
  699.         // data for SPI module
  700.         assign sd_datain = wr_n ? 8'hFF : din;
  701.  
  702.  
  703.  
  704.  
  705.  
  706.  
  707.  
  708. /////////////////////////////////////////////////////////////////////////////////////////////////
  709.  
  710.         ///////////////
  711.         // ATM ports //
  712.         ///////////////
  713.  
  714.         wire atm77_wr_fclk;
  715.         wire zxevbf_wr_fclk;
  716.  
  717.         assign atmF7_wr_fclk = ( (loa==ATMF7) && (a[8]==1'b1) && shadow && port_wr_fclk ); // xFF7 and x7F7 ports, NOT xEF7!
  718.         assign atm77_wr_fclk = ( (loa==ATM77) && shadow && port_wr_fclk );
  719.  
  720.         assign zxevbf_wr_fclk = ( (loa==ZXEVBF) && port_wr_fclk );
  721.  
  722.  
  723.         // port BF write
  724.         //
  725.         always @(posedge fclk, negedge rst_n)
  726.         if( !rst_n )
  727.         begin
  728.                 shadow_en_reg = 1'b0;
  729.                 romrw_en_reg  = 1'b0;
  730.         end
  731.         else if( zxevbf_wr_fclk )
  732.         begin
  733.                 shadow_en_reg <= din[0];
  734.                 romrw_en_reg  <= din[1];
  735.         end
  736.  
  737.         assign romrw_en = romrw_en_reg;
  738.  
  739.  
  740.  
  741.         // port xx77 write
  742.         always @(posedge fclk, negedge rst_n)
  743.         if( !rst_n )
  744.         begin
  745.                 atm_scr_mode = 3'b011;
  746.                 atm_turbo    = 1'b1;
  747.  
  748.                 atm_pen =   1'b1; // no manager,
  749.                 atm_cpm_n = 1'b0; // permanent dosen (shadow ports on)
  750.  
  751.  
  752.                 atm_pen2     = 1'b0;
  753.         end
  754.         else if( atm77_wr_fclk )
  755.         begin
  756.                 atm_scr_mode <= din[2:0];
  757.                 atm_turbo    <= din[3];
  758.                 atm_pen      <= ~a[8];
  759.                 atm_cpm_n    <=  a[9];
  760.                 atm_pen2     <= ~a[14];
  761.         end
  762.  
  763.  
  764.         // atm palette strobe and data
  765.         wire vg_wrFF_fclk;
  766.  
  767.         assign vg_wrFF_fclk = ( ( (loa==VGSYS)&&shadow ) && port_wr_fclk);
  768.  
  769.  
  770.         assign atm_palwr = vg_wrFF_fclk & atm_pen2;
  771.  
  772.         assign atm_paldata = { ~din[4], ~din[7], ~din[1], ~din[6], ~din[0], ~din[5] };
  773.  
  774.  
  775.  
  776.  
  777.  
  778.  
  779.         // covox/beeper writes
  780.  
  781.         assign beeper_wr = (loa==PORTFE) && portfe_wr_fclk;
  782.         assign covox_wr  = (loa==COVOX) && port_wr_fclk;
  783.  
  784.  
  785. endmodule
  786.  
  787.