Subversion Repositories pentevo

Rev

Rev 896 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

  1. // ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014
  2. //
  3. // most of pentevo ports are here
  4.  
  5. /*
  6.     This file is part of ZX-Evo Base Configuration firmware.
  7.  
  8.     ZX-Evo Base Configuration firmware is free software:
  9.     you can redistribute it and/or modify it under the terms of
  10.     the GNU General Public License as published by
  11.     the Free Software Foundation, either version 3 of the License, or
  12.     (at your option) any later version.
  13.  
  14.     ZX-Evo Base Configuration firmware is distributed in the hope that
  15.     it will be useful, but WITHOUT ANY WARRANTY; without even
  16.     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  17.     See the GNU General Public License for more details.
  18.  
  19.     You should have received a copy of the GNU General Public License
  20.     along with ZX-Evo Base Configuration firmware.
  21.     If not, see <http://www.gnu.org/licenses/>.
  22. */
  23.  
  24. `include "../include/tune.v"
  25.  
  26. module zports(
  27.  
  28.         input  wire        zclk,   // z80 clock
  29.         input  wire        fclk,  // global FPGA clock
  30.         input  wire        rst_n, // system reset
  31.  
  32.         input  wire        zpos,
  33.         input  wire        zneg,
  34.  
  35.  
  36.         input  wire [ 7:0] din,
  37.         output reg  [ 7:0] dout,
  38.         output wire        dataout,
  39.         input  wire [15:0] a,
  40.  
  41.         input  wire        iorq_n,
  42.         input  wire        mreq_n,
  43.         input  wire        m1_n,
  44.         input  wire        rd_n,
  45.         input  wire        wr_n,
  46.  
  47.         output reg         porthit, // when internal port hit occurs, this is 1, else 0; used for iorq1_n iorq2_n on zxbus
  48.         output reg         external_port, // asserts for AY and VG93 accesses
  49.  
  50.         output wire [15:0] ideout,
  51.         input  wire [15:0] idein,
  52.         output wire        idedataout, // IDE must IN data from IDE device when idedataout=0, else it OUTs
  53.         output wire [ 2:0] ide_a,
  54.         output wire        ide_cs0_n,
  55.         output wire        ide_cs1_n,
  56.         output wire        ide_rd_n,
  57.         output wire        ide_wr_n,
  58.  
  59.  
  60.         input  wire [ 4:0] keys_in, // keys (port FE)
  61.         input  wire [ 7:0] mus_in,  // mouse (xxDF)
  62.         input  wire [ 4:0] kj_in,
  63.  
  64.         output reg  [ 3:0] border,
  65.  
  66.  
  67.         input  wire        dos,
  68.  
  69.  
  70.         output wire        ay_bdir,
  71.         output wire        ay_bc1,
  72.  
  73.         output wire [ 7:0] p7ffd,
  74.         output wire [ 7:0] peff7,
  75.  
  76.         input  wire        tape_read,
  77.  
  78.         output wire        vg_cs_n,
  79.         input  wire        vg_intrq,
  80.         input  wire        vg_drq, // from vg93 module - drq + irq read
  81.         output wire        vg_wrFF,        // write strobe of #FF port
  82.  
  83.         output wire        sd_cs_n_val,
  84.         output wire        sd_cs_n_stb,
  85.         output wire        sd_start,
  86.         output wire [ 7:0] sd_datain,
  87.         input  wire [ 7:0] sd_dataout,
  88.  
  89.         // WAIT-ports related
  90.         //
  91.         output reg  [ 7:0] gluclock_addr,
  92.         //
  93.         output reg  [ 2:0] comport_addr,
  94.         //
  95.         output wire        wait_start_gluclock, // begin wait from some ports
  96.         output wire        wait_start_comport,  //
  97.         //
  98.         output reg         wait_rnw,   // whether it was read(=1) or write(=0)
  99.         output reg  [ 7:0] wait_write,
  100.         input  wire [ 7:0] wait_read,
  101.  
  102.  
  103.         output wire        atmF7_wr_fclk, // used in atm_pager.v
  104.  
  105.  
  106.         output reg  [ 2:0] atm_scr_mode, // RG0..RG2 in docs
  107.         output reg         atm_turbo,    // turbo mode ON
  108.         output reg         atm_pen,      // pager_off in atm_pager.v, NOT inverted!!!
  109.         output reg         atm_cpm_n,    // permanent dos on
  110.         output reg         atm_pen2,     // PEN2 - fucking palette mode, NOT inverted!!!
  111.  
  112.         output wire        romrw_en, // from port BF
  113.  
  114.  
  115.         output wire        pent1m_ram0_0, // d3.eff7
  116.         output wire        pent1m_1m_on,  // d2.eff7
  117.         output wire [ 5:0] pent1m_page,   // full 1 meg page number
  118.         output wire        pent1m_ROM,     // d4.7ffd
  119.  
  120.  
  121.         output wire        atm_palwr,   // palette write strobe
  122.         output wire [ 5:0] atm_paldata, // palette write data
  123.  
  124.         output wire        covox_wr,
  125.         output wire        beeper_wr,
  126.  
  127.         output wire        clr_nmi,
  128.  
  129.         output wire        fnt_wr,              // write to font_ram enabled
  130.  
  131.         // inputs from atm_pagers, to read back its config
  132.         input  wire [63:0] pages,
  133.         input  wire [ 7:0] ramnroms,
  134.         input  wire [ 7:0] dos7ffds,
  135.         input  wire [ 7:0] wrdisables,
  136.  
  137.         input  wire [ 5:0] palcolor,
  138.         input  wire [ 7:0] fontrom_readback,
  139.  
  140.         // ulaplus
  141.         output reg         up_ena,
  142.         output reg  [ 5:0] up_paladdr,
  143.         output wire [ 7:0] up_paldata,
  144.         output wire        up_palwr,
  145.  
  146.  
  147.  
  148.         // NMI generation
  149.         output reg         set_nmi,
  150.  
  151.         // break enable & address
  152.         output reg         brk_ena,
  153.         output reg  [15:0] brk_addr
  154. );
  155.  
  156.  
  157. `define IS_NIDE_REGS(x) ( (x[2:0]==3'b000) && (x[3]!=x[4]) )
  158. `define IS_NIDE_HIGH(x) ( x[7:0]==8'h11 )
  159. `define IS_PORT_NIDE(x) ( `IS_NIDE_REGS(x) || `IS_NIDE_HIGH(x) )
  160. `define NIDE_REGS 8'h10,8'h30,8'h50,8'h70,8'h90,8'hB0,8'hD0,8'hF0, \
  161.                   8'h08,8'h28,8'h48,8'h68,8'h88,8'hA8,8'hC8,8'hE8
  162.  
  163.         localparam PORTFE = 8'hFE;
  164.         localparam PORTF6 = 8'hF6;
  165.         localparam PORTF7 = 8'hF7;
  166.  
  167.         localparam NIDE10 = 8'h10;
  168.         localparam NIDE11 = 8'h11;
  169.         localparam NIDE30 = 8'h30;
  170.         localparam NIDE50 = 8'h50;
  171.         localparam NIDE70 = 8'h70;
  172.         localparam NIDE90 = 8'h90;
  173.         localparam NIDEB0 = 8'hB0;
  174.         localparam NIDED0 = 8'hD0;
  175.         localparam NIDEF0 = 8'hF0;
  176.         localparam NIDEC8 = 8'hC8;
  177.  
  178.         localparam PORTFD = 8'hFD;
  179.  
  180.         localparam VGCOM  = 8'h1F;
  181.         localparam VGTRK  = 8'h3F;
  182.         localparam VGSEC  = 8'h5F;
  183.         localparam VGDAT  = 8'h7F;
  184.         localparam VGSYS  = 8'hFF;
  185.  
  186.         localparam SAVPORT1 = 8'h2F;
  187.         localparam SAVPORT2 = 8'h4F;
  188.         localparam SAVPORT3 = 8'h6F;
  189.         localparam SAVPORT4 = 8'h8F;
  190.  
  191.         localparam KJOY   = 8'h1F;
  192.         localparam KMOUSE = 8'hDF;
  193.  
  194.         localparam SDCFG  = 8'h77;
  195.         localparam SDDAT  = 8'h57;
  196.  
  197.         localparam ATMF7  = 8'hF7;
  198.         localparam ATM77  = 8'h77;
  199.  
  200.         localparam ZXEVBE = 8'hBE; // xxBE config-read and nmi-end port
  201.         localparam ZXEVBF = 8'hBF; // xxBF config port
  202.         localparam ZXEVBRK = 8'hBD; // xxBD breakpoint address port    
  203.  
  204.         localparam COMPORT = 8'hEF; // F8EF..FFEF - rs232 ports
  205.  
  206.  
  207.         localparam COVOX   = 8'hFB;
  208.  
  209.        
  210.         localparam ULAPLUS = 8'h3B;
  211.  
  212.  
  213.  
  214.         reg port_wr;
  215.         reg port_rd;
  216.  
  217.         reg iowr_reg;
  218.         reg iord_reg;
  219.  
  220.  
  221.         reg port_wr_fclk,
  222.             port_rd_fclk,
  223.             mem_wr_fclk;
  224.  
  225.         reg [1:0] iowr_reg_fclk,
  226.                   iord_reg_fclk;
  227.  
  228.         reg [1:0] memwr_reg_fclk;
  229.  
  230.  
  231.         wire [7:0] loa;
  232.  
  233.  
  234.  
  235.  
  236.         wire ideout_hi_wr;
  237.         wire idein_lo_rd;
  238.         reg [7:0] idehiin; // IDE high part read register: low part is read directly to Z80 bus,
  239.                            // while high part is remembered here
  240.         reg ide_ports; // ide ports selected
  241.  
  242.         reg ide_rd_trig; // nemo-divide read trigger
  243.         reg ide_rd_latch; // to save state of trigger during read cycle
  244.  
  245.         reg ide_wrlo_trig,  ide_wrhi_trig;  // nemo-divide write triggers
  246.         reg ide_wrlo_latch, ide_wrhi_latch; // save state during write cycles
  247.  
  248.  
  249.  
  250.         reg  [15:0] idewrreg; // write register, either low or high part is pre-written here,
  251.                               // while other part is out directly from Z80 bus
  252.  
  253.         wire [ 7:0] iderdeven; // to control read data from "even" ide ports (all except #11)
  254.         wire [ 7:0] iderdodd;  // read data from "odd" port (#11)
  255.  
  256.  
  257.  
  258.         reg pre_bc1,pre_bdir;
  259.  
  260.         wire gluclock_on;
  261.  
  262.  
  263.  
  264.         reg  shadow_en_reg; //bit0.xxBF
  265.         reg   romrw_en_reg; //bit1.xxBF
  266.         reg  fntw_en_reg;       //bit2.xxBF
  267.  
  268.         wire shadow;
  269.  
  270.  
  271.  
  272.         reg [7:0] portbemux;
  273.  
  274.  
  275.  
  276.         reg [7:0] savport [3:0];
  277.         reg [5:0] vgFF;
  278.  
  279.  
  280.         reg [7:0] up_lastwritten;
  281.  
  282.  
  283.         assign shadow = dos || shadow_en_reg;
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.         assign loa=a[7:0];
  291.  
  292.         always @*
  293.         begin
  294.                 if( (loa==PORTFE) || (loa==PORTF6) ||
  295.                     (loa==PORTFD) || (loa==8'hFC)  ||
  296.  
  297.                     `IS_PORT_NIDE(loa) ||
  298. //                  (loa==NIDE10) || (loa==NIDE11) || (loa==NIDE30) || (loa==NIDE50) || (loa==NIDE70) ||
  299. //                  (loa==NIDE90) || (loa==NIDEB0) || (loa==NIDED0) || (loa==NIDEF0) || (loa==NIDEC8) ||
  300.  
  301.                     (loa==KMOUSE) ||
  302.  
  303.                     ( (loa==VGCOM)&&shadow ) || ( (loa==VGTRK)&&shadow ) || ( (loa==VGSEC)&&shadow ) || ( (loa==VGDAT)&&shadow ) ||
  304.                     ( (loa==VGSYS)&&shadow ) || ( (loa==KJOY)&&(!shadow) ) ||
  305.  
  306.                     ( (loa==SAVPORT1)&&shadow ) || ( (loa==SAVPORT2)&&shadow ) ||
  307.                     ( (loa==SAVPORT3)&&shadow ) || ( (loa==SAVPORT4)&&shadow ) ||
  308.  
  309.  
  310.                     ( (loa==PORTF7)&&(!shadow) ) || ( (loa==SDCFG)&&(!shadow) ) || ( (loa==SDDAT) ) ||
  311.  
  312.                     ( (loa==ATMF7)&&shadow ) || ( (loa==ATM77)&&shadow ) ||
  313.  
  314.                     ( loa==ZXEVBF ) || ( loa==ZXEVBE) || ( loa==ZXEVBRK) || ( loa==COMPORT ) ||
  315.  
  316.                     ( loa==ULAPLUS)
  317.                   )
  318.  
  319.  
  320.  
  321.                         porthit = 1'b1;
  322.                 else
  323.                         porthit = 1'b0;
  324.         end
  325.  
  326.         always @*
  327.         begin
  328.                 if( ((loa==PORTFD) && a[15]) || // 0xBFFD/0xFFFD ports
  329.                     (( (loa==VGCOM)&&shadow ) || ( (loa==VGTRK)&&shadow ) || ( (loa==VGSEC)&&shadow ) || ( (loa==VGDAT)&&shadow )) ) // vg93 ports
  330.                         external_port = 1'b1;
  331.                 else
  332.                         external_port = 1'b0;
  333.         end
  334.  
  335.         assign dataout = porthit & (~iorq_n) & (~rd_n) & (~external_port);
  336.  
  337.  
  338.  
  339.         // this is zclk-synchronous strobes
  340.         always @(posedge zclk)
  341.         begin
  342.                 iowr_reg <= ~(iorq_n | wr_n);
  343.                 iord_reg <= ~(iorq_n | rd_n);
  344.  
  345.                 if( (!iowr_reg) && (!iorq_n) && (!wr_n) )
  346.                         port_wr <= 1'b1;
  347.                 else
  348.                         port_wr <= 1'b0;
  349.  
  350.  
  351.                 if( (!iord_reg) && (!iorq_n) && (!rd_n) )
  352.                         port_rd <= 1'b1;
  353.                 else
  354.                         port_rd <= 1'b0;
  355.         end
  356.  
  357.  
  358.  
  359.  
  360.         // fclk-synchronous stobes
  361.         //
  362.         always @(posedge fclk) if( zpos )
  363.         begin
  364.                 iowr_reg_fclk[0] <= ~(iorq_n | wr_n);
  365.                 iord_reg_fclk[0] <= ~(iorq_n | rd_n);
  366.         end
  367.  
  368.         always @(posedge fclk)
  369.         begin
  370.                 iowr_reg_fclk[1] <= iowr_reg_fclk[0];
  371.                 iord_reg_fclk[1] <= iord_reg_fclk[0];
  372.         end
  373.  
  374.         always @(posedge fclk)
  375.         begin
  376.                 port_wr_fclk <= iowr_reg_fclk[0] && (!iowr_reg_fclk[1]);
  377.                 port_rd_fclk <= iord_reg_fclk[0] && (!iord_reg_fclk[1]);
  378.         end
  379.  
  380.         always @(posedge fclk)
  381.                 memwr_reg_fclk[1:0] <= { memwr_reg_fclk[0], ~(mreq_n | wr_n) };
  382.  
  383.         always @(posedge fclk)
  384.                 mem_wr_fclk <= memwr_reg_fclk[0] && (!memwr_reg_fclk[1]);
  385.  
  386.  
  387.  
  388.         // dout data
  389.         always @*
  390.         begin
  391.                 case( loa )
  392.                 PORTFE:
  393.                         dout = { 1'b1, tape_read, 1'b0, keys_in };
  394.                 PORTF6:
  395.                         dout = { 1'b1, tape_read, 1'b0, keys_in };
  396.  
  397.  
  398.                 `NIDE_REGS:
  399.                         dout = iderdeven;
  400.                 NIDE11:
  401.                         dout = iderdodd;
  402.  
  403.  
  404.                 //PORTFD:
  405.  
  406.                 VGSYS:
  407.                         dout = { vg_intrq, vg_drq, vgFF }; // 6'b111111 };
  408.  
  409.                 SAVPORT1, SAVPORT2, SAVPORT3, SAVPORT4:
  410.                         dout = savport[ loa[6:5] ];
  411.  
  412.  
  413.                 KJOY:
  414.                         dout = {3'b000, kj_in};
  415.                 KMOUSE:
  416.                         dout = mus_in;
  417.  
  418.                 SDCFG:
  419.                         dout = 8'h00; // always SD inserted, SD is in R/W mode
  420.                 SDDAT:
  421.                         dout = sd_dataout;
  422.  
  423.  
  424.                 PORTF7: begin
  425.                         if( !a[14] && (a[8]^shadow) && gluclock_on ) // $BFF7 - data i/o
  426.                                 dout = wait_read;
  427.                         else // any other $xxF7 port
  428.                                 dout = 8'hFF;
  429.                 end
  430.  
  431.                 COMPORT: begin
  432.                         dout = wait_read; // $F8EF..$FFEF
  433.                 end
  434.  
  435.                 ZXEVBF: begin
  436.                         dout = { 3'b000, brk_ena, set_nmi, fntw_en_reg, romrw_en_reg, shadow_en_reg };
  437.                 end
  438.  
  439.                 ZXEVBE: begin
  440.                         dout = portbemux;
  441.                 end
  442.  
  443.                 ULAPLUS: begin
  444.                         dout = up_lastwritten;
  445.                 end
  446.  
  447.  
  448.                 default:
  449.                         dout = 8'hFF;
  450.                 endcase
  451.         end
  452.  
  453.  
  454.  
  455.         assign portfd_wr    = ( (loa==PORTFD || loa==8'hFC) && port_wr);
  456.  
  457.         // F7 ports (like EFF7) are accessible in shadow mode but at addresses like EEF7, DEF7, BEF7 so that
  458.         // there are no conflicts in shadow mode with ATM xFF7 and x7F7 ports
  459.         assign portf7_wr    = ( (loa==PORTF7) && (a[8]==1'b1) && port_wr && (!shadow) ) ||
  460.                               ( (loa==PORTF7) && (a[8]==1'b0) && port_wr &&   shadow  ) ;
  461.  
  462.         assign portf7_rd    = ( (loa==PORTF7) && (a[8]==1'b1) && port_rd && (!shadow) ) ||
  463.                               ( (loa==PORTF7) && (a[8]==1'b0) && port_rd &&   shadow  ) ;
  464.  
  465.         assign vg_wrFF = ( ( (loa==VGSYS)&&shadow ) && port_wr);
  466.         always @(posedge zclk) if( vg_wrFF )
  467.                 vgFF <= din[5:0];
  468.  
  469.         assign comport_wr   = ( (loa==COMPORT) && port_wr);
  470.         assign comport_rd   = ( (loa==COMPORT) && port_rd);
  471.  
  472.        
  473.         assign zxevbrk_wr_fclk = ( (loa==ZXEVBRK) && port_wr_fclk);
  474.  
  475.  
  476.  
  477.  
  478.  
  479.         // break address write
  480.         always @(posedge fclk)
  481.         if( zxevbrk_wr_fclk)
  482.         begin
  483.                 if( !a[8] )
  484.                         brk_addr[ 7:0] <= din;
  485.                 else // a[8]==1
  486.                         brk_addr[15:8] <= din;
  487.         end
  488.  
  489.  
  490.  
  491.  
  492.  
  493.         //border port FE
  494.         wire portwe_wr_fclk;
  495.  
  496.         assign portfe_wr_fclk = (((loa==PORTFE) || (loa==PORTF6) || (loa==8'hFC)) && port_wr_fclk);
  497.  
  498.         always @(posedge fclk)
  499.         if( portfe_wr_fclk )
  500.                 border <= { ~a[3], din[2:0] };
  501.  
  502.  
  503.  
  504.  
  505.  
  506.  
  507.         // IDE ports
  508.  
  509.         // IDE physical ports (that go to IDE device)
  510.         always @(loa)
  511.         if( `IS_NIDE_REGS(loa) )
  512.                 ide_ports = 1'b1;
  513.         else
  514.                 ide_ports = 1'b0;
  515.  
  516.  
  517.         assign idein_lo_rd  = port_rd && (loa==NIDE10) && (!ide_rd_trig);
  518.  
  519.         // control read & write triggers, which allow nemo-divide mod to work.
  520.         //
  521.         // read trigger:
  522.         always @(posedge zclk)
  523.         begin
  524.                 if( (loa==NIDE10) && port_rd && !ide_rd_trig )
  525.                         ide_rd_trig <= 1'b1;
  526.                 else if( ( ide_ports || (loa==NIDE11) ) && ( port_rd || port_wr ) )
  527.                         ide_rd_trig <= 1'b0;
  528.         end
  529.         //
  530.         // two triggers for write sequence...
  531.         always @(posedge zclk)
  532.         if( ( ide_ports || (loa==NIDE11) ) && ( port_rd || port_wr ) )
  533.         begin
  534.                 if( (loa==NIDE11) && port_wr )
  535.                         ide_wrhi_trig <= 1'b1;
  536.                 else
  537.                         ide_wrhi_trig <= 1'b0;
  538.                 //
  539.                 if( (loa==NIDE10) && port_wr && !ide_wrhi_trig && !ide_wrlo_trig )
  540.                         ide_wrlo_trig <= 1'b1;
  541.                 else
  542.                         ide_wrlo_trig <= 1'b0;
  543.         end
  544.  
  545.         // normal read: #10(low), #11(high)
  546.         // divide read: #10(low), #10(high)
  547.         //
  548.         // normal write: #11(high), #10(low)
  549.         // divide write: #10(low),  #10(high)
  550.  
  551.  
  552.         always @(posedge zclk)
  553.         begin
  554.                 if( port_wr && (loa==NIDE11) )
  555.                         idewrreg[15:8] <= din;
  556.  
  557.                 if( port_wr && (loa==NIDE10) && !ide_wrlo_trig )
  558.                         idewrreg[ 7:0] <= din;
  559.         end
  560.  
  561.  
  562.  
  563.  
  564.         always @(posedge zclk)
  565.         if( idein_lo_rd )
  566.                         idehiin <= idein[15:8];
  567.  
  568.  
  569.         assign ide_a = a[7:5];
  570.  
  571.  
  572.         // This is unknown shit... Probably need more testing with old WD
  573.         // drives WITHOUT this commented fix.
  574.         //
  575.         // trying to fix old WD drives...
  576.         //assign ide_cs0_n = iorq_n | (rd_n&wr_n) | (~ide_ports) | (~(loa!=NIDEC8));
  577.         //assign ide_cs1_n = iorq_n | (rd_n&wr_n) | (~ide_ports) | (~(loa==NIDEC8));
  578.         // fix ends...
  579.  
  580.  
  581.         assign ide_cs0_n = (~ide_ports) | (~(loa!=NIDEC8));
  582.         assign ide_cs1_n = (~ide_ports) | (~(loa==NIDEC8));
  583.  
  584.  
  585.         // generate read cycles for IDE as usual, except for reading #10
  586.         // instead of #11 for high byte (nemo-divide). I use additional latch
  587.         // since 'ide_rd_trig' clears during second Z80 IO read cycle to #10
  588.         always @* if( rd_n ) ide_rd_latch <= ide_rd_trig;
  589.         //
  590.         assign ide_rd_n = iorq_n | rd_n | (~ide_ports) | (ide_rd_latch && (loa==NIDE10));
  591.  
  592.         always @* if( wr_n ) ide_wrlo_latch <= ide_wrlo_trig; // same for write triggers
  593.         always @* if( wr_n ) ide_wrhi_latch <= ide_wrhi_trig; //
  594.         //
  595.         assign ide_wr_n = iorq_n | wr_n | (~ide_ports) | ( (loa==NIDE10) && !ide_wrlo_latch && !ide_wrhi_latch );
  596.                                                   // do NOT generate IDE write, if neither of ide_wrhi|lo latches
  597.                                                   // set and writing to NIDE10
  598.  
  599.  
  600.  
  601. //      assign idedataout = ide_rd_n;
  602.         assign idedataout = ~ide_wr_n; // shit-fix in try to fix IDE errors
  603.         // warning: this fix kinda blind-picking, good way is to
  604.         // have idedataout lead wr or rd strobes. also good point to disable data ringing
  605.         // on ide data bus while not accessing IDE
  606.  
  607.  
  608.         // data read by Z80 from IDE
  609.         //
  610.         assign iderdodd[ 7:0] = idehiin[ 7:0];
  611.         //
  612.         assign iderdeven[ 7:0] = (ide_rd_latch && (loa==NIDE10)) ? idehiin[ 7:0] : idein[ 7:0];
  613.  
  614.         // data written to IDE from Z80
  615.         //
  616.         assign ideout[15:8] = ide_wrhi_latch ? idewrreg[15:8] : din[ 7:0];
  617.         assign ideout[ 7:0] = ide_wrlo_latch ? idewrreg[ 7:0] : din[ 7:0];
  618.  
  619.  
  620.  
  621.  
  622.  
  623.  
  624.  
  625.         // AY control
  626.         always @*
  627.         begin
  628.                 pre_bc1 = 1'b0;
  629.                 pre_bdir = 1'b0;
  630.  
  631.                 if( loa==PORTFD )
  632.                 begin
  633.                         if( a[15:14]==2'b11 )
  634.                         begin
  635.                                 pre_bc1=1'b1;
  636.                                 pre_bdir=1'b1;
  637.                         end
  638.                         else if( a[15:14]==2'b10 )
  639.                         begin
  640.                                 pre_bc1=1'b0;
  641.                                 pre_bdir=1'b1;
  642.                         end
  643.                 end
  644.         end
  645.  
  646.         assign ay_bc1  = pre_bc1  & (~iorq_n) & ((~rd_n)|(~wr_n));
  647.         assign ay_bdir = pre_bdir & (~iorq_n) & (~wr_n);
  648.  
  649.  
  650.  
  651.         // 7FFD port
  652.         reg [7:0] p7ffd_int,peff7_int;
  653.         reg p7ffd_rom_int;
  654.         wire block7ffd;
  655.         wire block1m;
  656.  
  657.         always @(posedge zclk, negedge rst_n)
  658.         begin
  659.                 if( !rst_n )
  660.                         p7ffd_int <= 7'h00;
  661.                 else if( (a[15]==1'b0) && portfd_wr && (!block7ffd) )
  662.                         p7ffd_int <= din; // 2..0 - page, 3 - screen, 4 - rom, 5 - block48k, 6..7 -
  663.         end
  664.  
  665.         always @(posedge zclk, negedge rst_n)
  666.         if( !rst_n )
  667.                         p7ffd_rom_int <= 1'b0;
  668.         else
  669.                 if( (a[15]==1'b0) && portfd_wr && (!block7ffd) )
  670.                         p7ffd_rom_int <= din[4];
  671.  
  672.  
  673.         assign block7ffd=p7ffd_int[5] & block1m;
  674.  
  675.  
  676.         // EFF7 port
  677.         always @(posedge zclk, negedge rst_n)
  678.         begin
  679.                 if( !rst_n )
  680.                         peff7_int <= 8'h00;
  681.                 else if( !a[12] && portf7_wr && (!shadow) ) // EEF7 in shadow mode is abandoned!
  682.                         peff7_int <= din; // 4 - turbooff, 0 - p16c on, 2 - block1meg
  683.         end
  684.         assign block1m = peff7_int[2];
  685.  
  686.         assign p7ffd = { (block1m ? 3'b0 : p7ffd_int[7:5]),p7ffd_rom_int,p7ffd_int[3:0]};
  687.  
  688.         assign peff7 = block1m ? { peff7_int[7], 1'b0, peff7_int[5], peff7_int[4], 3'b000, peff7_int[0] } : peff7_int;
  689.  
  690.  
  691.         assign pent1m_ROM       = p7ffd_int[4];
  692.         assign pent1m_page[5:0] = { p7ffd_int[7:5], p7ffd_int[2:0] };
  693.         assign pent1m_1m_on     = ~peff7_int[2];
  694.         assign pent1m_ram0_0    = peff7_int[3];
  695.  
  696.  
  697.  
  698.  
  699.         // gluclock ports (bit7:eff7 is above)
  700.  
  701.         assign gluclock_on = peff7_int[7] || shadow; // in shadow mode EEF7 is abandoned: instead, gluclock access
  702.                                                      // is ON forever in shadow mode.
  703.  
  704.         always @(posedge zclk)
  705.         begin
  706.                 if( gluclock_on && portf7_wr ) // gluclocks on
  707.                 begin
  708.                         if( !a[13] ) // $DFF7 - addr reg
  709.                                 gluclock_addr <= din;
  710.  
  711.                         // write to waiting register is not here - in separate section managing wait_write
  712.                 end
  713.         end
  714.  
  715.  
  716.         // comports
  717.  
  718.         always @(posedge zclk)
  719.         begin
  720.                 if( comport_wr || comport_rd )
  721.                         comport_addr <= a[10:8 ];
  722.         end
  723.  
  724.  
  725.  
  726.         // write to wait registers
  727.         always @(posedge zclk)
  728.         begin
  729.                 // gluclocks
  730.                 if( gluclock_on && portf7_wr && !a[14] ) // $BFF7 - data reg
  731.                         wait_write <= din;
  732.                 // com ports
  733.                 else if( comport_wr ) // $F8EF..$FFEF - comports
  734.                         wait_write <= din;
  735.         end
  736.  
  737.         // wait from wait registers
  738.         //
  739.         // ACHTUNG!!!! here portxx_wr are ON Z80 CLOCK! logic must change when moving to fclk strobes
  740.         //
  741.         assign wait_start_gluclock = ( gluclock_on && !a[14] && (portf7_rd || portf7_wr) ); // $BFF7 - gluclock r/w
  742.         //
  743.         assign wait_start_comport = ( comport_rd || comport_wr );
  744.         //
  745.         //
  746.         always @(posedge zclk) // wait rnw - only meanful during wait
  747.         begin
  748.                 if( port_wr )
  749.                         wait_rnw <= 1'b0;
  750.  
  751.                 if( port_rd )
  752.                         wait_rnw <= 1'b1;
  753.         end
  754.  
  755.  
  756.  
  757.  
  758.  
  759.         // VG93 control
  760.         assign vg_cs_n =  (~shadow) | iorq_n | (rd_n & wr_n) | ( ~((loa==VGCOM)|(loa==VGTRK)|(loa==VGSEC)|(loa==VGDAT)) );
  761.  
  762.  
  763.  
  764.  
  765.  
  766.  
  767.  
  768.  
  769. // SD card (z-controlâ••r compatible)
  770.  
  771.         wire sdcfg_wr,sddat_wr,sddat_rd;
  772.  
  773.         assign sdcfg_wr = ( (loa==SDCFG) && port_wr_fclk && (!shadow) )                  ||
  774.                           ( (loa==SDDAT) && port_wr_fclk &&   shadow  && (a[15]==1'b1) ) ;
  775.  
  776.         assign sddat_wr = ( (loa==SDDAT) && port_wr_fclk && (!shadow) )                  ||
  777.                           ( (loa==SDDAT) && port_wr_fclk &&   shadow  && (a[15]==1'b0) ) ;
  778.  
  779.         assign sddat_rd = ( (loa==SDDAT) && port_rd_fclk              );
  780.  
  781.         // SDCFG write - sdcs_n control
  782.         assign sd_cs_n_stb = sdcfg_wr;
  783.         assign sd_cs_n_val = din[1];
  784.  
  785.  
  786.         // start signal for SPI module with resyncing to fclk
  787.  
  788.         assign sd_start = sddat_wr || sddat_rd;
  789.  
  790.         // data for SPI module
  791.         assign sd_datain = sddat_rd ? 8'hFF : din;
  792.  
  793.  
  794.  
  795.  
  796.  
  797.  
  798.  
  799. /////////////////////////////////////////////////////////////////////////////////////////////////
  800.  
  801.         ///////////////
  802.         // ATM ports //
  803.         ///////////////
  804.  
  805.         wire atm77_wr_fclk;
  806.         wire zxevbf_wr_fclk;
  807.  
  808.         assign atmF7_wr_fclk = ( (loa==ATMF7) && (a[8]==1'b1) && shadow && port_wr_fclk ); // xFF7 and x7F7 ports, NOT xEF7!
  809.         assign atm77_wr_fclk = ( (loa==ATM77) && shadow && port_wr_fclk );
  810.  
  811.         assign zxevbf_wr_fclk = ( (loa==ZXEVBF) && port_wr_fclk );
  812.  
  813.  
  814.         // port BF write
  815.         //
  816.         always @(posedge fclk, negedge rst_n)
  817.         if( !rst_n )
  818.         begin
  819.                 shadow_en_reg <= 1'b0;
  820.                 romrw_en_reg  <= 1'b0;
  821.                 fntw_en_reg   <= 1'b0;
  822.                 set_nmi       <= 1'b0;
  823.                 brk_ena       <= 1'b0;
  824.         end
  825.         else if( zxevbf_wr_fclk )
  826.         begin
  827.                 shadow_en_reg <= din[0];
  828.                 romrw_en_reg  <= din[1];
  829.                 fntw_en_reg   <= din[2];
  830.                 set_nmi       <= din[3];
  831.                 brk_ena       <= din[4];
  832.         end
  833.  
  834.         assign romrw_en = romrw_en_reg;
  835.  
  836.  
  837.  
  838.         // port xx77 write
  839.         always @(posedge fclk, negedge rst_n)
  840.         if( !rst_n )
  841.         begin
  842.                 atm_scr_mode = 3'b011;
  843.                 atm_turbo    = 1'b0;
  844.  
  845.                 atm_pen =   1'b1; // no manager,
  846.                 atm_cpm_n = 1'b0; // permanent dosen (shadow ports on)
  847.  
  848.  
  849.                 atm_pen2     = 1'b0;
  850.         end
  851.         else if( atm77_wr_fclk )
  852.         begin
  853.                 atm_scr_mode <= din[2:0];
  854.                 atm_turbo    <= din[3];
  855.                 atm_pen      <= ~a[8];
  856.                 atm_cpm_n    <=  a[9];
  857.                 atm_pen2     <= ~a[14];
  858.         end
  859.  
  860.  
  861.         // atm palette strobe and data
  862.         wire vg_wrFF_fclk;
  863.  
  864.         assign vg_wrFF_fclk = ( ( (loa==VGSYS)&&shadow ) && port_wr_fclk);
  865.  
  866.  
  867.         assign atm_palwr = vg_wrFF_fclk & atm_pen2;
  868.  
  869.         assign atm_paldata = { ~din[4], ~din[7], ~din[1], ~din[6], ~din[0], ~din[5] };
  870.  
  871.  
  872.  
  873.         // port BE write
  874.         assign clr_nmi = ( (loa==ZXEVBE) && port_wr_fclk );
  875.  
  876.  
  877.  
  878.  
  879.         // covox/beeper writes
  880.  
  881.         assign beeper_wr = (loa==PORTFE) && portfe_wr_fclk;
  882.         assign covox_wr  = (loa==COVOX) && port_wr_fclk;
  883.  
  884.  
  885.  
  886.         // font write enable
  887.         assign fnt_wr = fntw_en_reg && mem_wr_fclk;
  888.  
  889.  
  890.  
  891.         // port BE read
  892.  
  893.         always @*
  894.         case( a[12:8] )
  895.  
  896.         5'h0: portbemux = pages[ 7:0 ];
  897.         5'h1: portbemux = pages[15:8 ];
  898.         5'h2: portbemux = pages[23:16];
  899.         5'h3: portbemux = pages[31:24];
  900.         5'h4: portbemux = pages[39:32];
  901.         5'h5: portbemux = pages[47:40];
  902.         5'h6: portbemux = pages[55:48];
  903.         5'h7: portbemux = pages[63:56];
  904.  
  905.         5'h8: portbemux = ramnroms;
  906.         5'h9: portbemux = dos7ffds;
  907.  
  908.         5'hA: portbemux = p7ffd_int;
  909.         5'hB: portbemux = peff7_int;
  910.  
  911.         5'hC: portbemux = { ~atm_pen2, atm_cpm_n, ~atm_pen, dos, atm_turbo, atm_scr_mode };
  912.  
  913.         5'hD: portbemux = { ~palcolor[4], ~palcolor[2], ~palcolor[0], ~palcolor[5], 2'b11, ~palcolor[3], ~palcolor[1] };
  914. //      assign atm_paldata = { ~din[4], ~din[7], ~din[1], ~din[6], ~din[0], ~din[5] };
  915. //  {GgRrBb} -> {grbG11RB}
  916. // was: 76543210 -> 471605
  917. // now:             543210 -> 4205xx31
  918.  
  919.         5'hE: portbemux = fontrom_readback;
  920.         5'hF: portbemux = { 4'bXXXX, border };
  921.  
  922.         5'h10: portbemux = brk_addr[7:0];
  923.         5'h11: portbemux = brk_addr[15:8];
  924.  
  925.         5'h12: portbemux = wrdisables;
  926.  
  927.         default: portbemux = 8'bXXXXXXXX;
  928.  
  929.         endcase
  930.  
  931.  
  932.  
  933.  
  934.  
  935.         // savelij ports write
  936.         //
  937.         always @(posedge fclk)
  938.         if( port_wr_fclk && shadow )
  939.         begin
  940.                 if( (loa==SAVPORT1) ||
  941.                     (loa==SAVPORT2) ||
  942.                     (loa==SAVPORT3) ||
  943.                     (loa==SAVPORT4) )
  944.                         savport[ loa[6:5] ] <= din;
  945.         end
  946.  
  947.  
  948.  
  949.  
  950.         // ULAPLUS ports
  951.         reg up_select; // 0 -- ena/dis, 1 -- palette write
  952.         //
  953.         wire up_wr = port_wr_fclk && (loa==ULAPLUS);
  954.         //
  955.         always @(posedge fclk)
  956.         if( up_wr && !a[14] )
  957.         begin
  958.                 if( !din[7] &&  din[6] )
  959.                 begin
  960.                         up_select <= 1'b1;
  961.                 end
  962.  
  963.                 if( !din[7] && !din[6] )
  964.                 begin
  965.                         up_select <= 1'b0;
  966.                         up_paladdr[5:0] <= din[5:0];
  967.                 end
  968.         end
  969.         //
  970.         always @(posedge fclk) if( up_wr && a[14] )
  971.                 up_lastwritten <= din;
  972.         //
  973.         assign up_palwr = up_wr && a[14] && !up_select;
  974.         //
  975.         always @(posedge fclk, negedge rst_n)
  976.         if( !rst_n )
  977.                 up_ena <= 1'b0;
  978.         else if( up_wr && a[14] && up_select )
  979.                 up_ena <= din[0];
  980.         //
  981.         assign up_paldata = {din[4:2],din[7:5],din[1:0]}; // G3R3B2 to R3G3B2
  982.  
  983. endmodule
  984.  
  985.