Subversion Repositories pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

  1. `include "../include/tune.v"
  2.  
  3. // PentEvo project (c) NedoPC 2008-2009
  4. //
  5. // vg93 interface
  6. //
  7. // #1F - vg93 command/state reg {0,0} - not here!
  8. // #3F - vg93 track register    {0,1} - not here!
  9. // #5F - vg93 sector register   {1,0} - not here!
  10. // #7F - vg93 data register     {1,1} - not here!
  11. // #FF - output "system" reg/input (DRQ+IRQ) reg
  12. //   output: d6 - FM/MFM               - NOT USED ANYWHERE! -> skipped
  13. //           d4 - disk side            - inverted out
  14. //           d3 - head load            - for HRDY pin of vg93
  15. //           d2 - /RESET for vg93      - must be zero at system reset
  16. //           d1:d0 - disk drive select - to the 74138
  17. //    input: d7 - /INTRQ - resynced at CPU clock
  18. //           d6 - /DRQ   - .....................
  19. //
  20. // current limitations:
  21. //  1. read clock regenerator is made of simple counter, as in pentagon128
  22. //  1. write precompensation is based only on SL/SR/TR43 signals
  23.  
  24. module vg93(
  25.  
  26.         input zclk, // Z80 cpu clock
  27.         input rst_n,
  28.         input fclk, // fpga 28 MHz clock
  29.  
  30.         output vg_clk,
  31.         output reg vg_res_n,
  32.  
  33.         input [7:0] din,  // data input from CPU
  34.         output intrq,drq, // output signals for the read #FF (not here)
  35.         input vg_wrFF,    // when TRDOS port #FF written - positive strobe
  36.  
  37.  
  38.         output reg vg_hrdy,
  39.         output reg vg_rclk,
  40.         output reg vg_rawr,
  41.         output reg [1:0] vg_a, // disk drive selection
  42.         output reg vg_wrd,
  43.         output reg vg_side,
  44.  
  45.         input step, // step signal from VG93
  46.         input vg_sl,vg_sr,vg_tr43,
  47.         input rdat_n,
  48.         input vg_wf_de,
  49.         input vg_drq,
  50.         input vg_irq,
  51.         input vg_wd
  52. );
  53.  
  54.  
  55.         localparam WRDELAY_OUTER_LEFT  = 4'd4;
  56.         localparam WRDELAY_OUTER_RIGHT = 4'd11;
  57.         localparam WRDELAY_INNER_LEFT  = 4'd0;  // minimal delay is for maximum shift left
  58.         localparam WRDELAY_INNER_RIGHT = 4'd14; // maximal delay is for maximum shift right
  59.         localparam WRDELAY_STANDARD    = 4'd7;  // no-shift
  60.  
  61.  
  62.  
  63.  
  64.         reg [2:0] vgclk_div7;
  65.         wire vgclk_strobe7;
  66.         reg [1:0] vgclk_div4;
  67.  
  68.         reg [2:0] step_pulse;
  69.         reg [2:0] drq_pulse;
  70.         wire step_pospulse;
  71.         wire  drq_pospulse;
  72.         reg turbo_state;
  73.  
  74.         reg [1:0] intrq_sync;
  75.         reg [1:0] drq_sync;
  76.  
  77.         reg [1:0] sl_sync,sr_sync,tr43_sync;
  78.         reg [2:0] wd_sync;
  79.         wire sl,sr,tr43,wd;
  80.  
  81.         reg [3:0] wrdelay_cnt;
  82.         wire delay_end;
  83.  
  84.         reg [3:0] wrwidth_cnt;
  85.         wire wrwidth_ena;
  86.  
  87.  
  88.         reg [4:0] rdat_sync;
  89.         reg rdat_edge1, rdat_edge2;
  90.         wire rdat;
  91.  
  92.         reg [3:0] rwidth_cnt;
  93.         wire rwidth_ena;
  94.         reg [5:0] rclk_cnt;
  95.         wire rclk_strobe;
  96.  
  97.  
  98.  
  99.         // VG93 clocking and turbo-mode
  100.  
  101.         always @(posedge fclk)
  102.         begin
  103.                 step_pulse[2:0] <= { step_pulse[1:0], step};
  104.                  drq_pulse[2:0] <= {  drq_pulse[1:0], vg_drq};
  105.         end
  106.  
  107.         assign step_pospulse = ( step_pulse[1] & (~step_pulse[2]) );
  108.         assign  drq_pospulse = (  drq_pulse[1] & ( ~drq_pulse[2]) );
  109.  
  110.         always @(posedge fclk,negedge rst_n)
  111.         begin
  112.                 if( !rst_n )
  113.                         turbo_state <= 1'b0;
  114.                 else
  115.                 begin
  116.                         if( drq_pospulse )
  117.                                 turbo_state <= 1'b0;
  118.                         else if( step_pospulse )
  119.                                 turbo_state <= 1'b1;
  120.                 end
  121.         end
  122.  
  123.  
  124.  
  125.         assign vgclk_strobe7 = (vgclk_div7[2:1] == 2'b11); // 28/7=4MHz freq strobe
  126.  
  127.         always @(posedge fclk)
  128.         begin
  129.                 if( vgclk_strobe7 )
  130.                         vgclk_div7 <= 3'd0;
  131.                 else
  132.                         vgclk_div7 <= vgclk_div7 + 3'd1;
  133.         end
  134.  
  135.         always @(posedge fclk)
  136.         begin
  137.                 if( vgclk_strobe7 )
  138.                 begin
  139.                         vgclk_div4[0] <= ~vgclk_div4[1];
  140.  
  141.                         if( turbo_state )
  142.                                 vgclk_div4[1] <= ~vgclk_div4[1];
  143.                         else
  144.                                 vgclk_div4[1] <= vgclk_div4[0];
  145.                 end
  146.         end
  147.  
  148.         assign vg_clk = vgclk_div4[1];
  149.  
  150.  
  151.         // input/output for TR-DOS port #FF
  152.  
  153.         always @(posedge zclk, negedge rst_n) // CHANGE IF GO TO THE positive/negative strobes instead of zclk!
  154.         begin
  155.                 if( !rst_n )
  156.                         vg_res_n <= 1'b0;
  157.                 else if( vg_wrFF )
  158.                         { vg_side, vg_hrdy, vg_res_n, vg_a } <= { (~din[4]),din[3],din[2],din[1:0] };
  159.         end
  160.  
  161.         always @(posedge zclk)
  162.         begin
  163.                 intrq_sync[1:0] <= {intrq_sync[0],vg_irq};
  164.                 drq_sync[1:0] <= {drq_sync[0],vg_drq};
  165.         end
  166.  
  167.         assign intrq = intrq_sync[1];
  168.         assign drq   =   drq_sync[1];
  169.  
  170.  
  171.  
  172.  
  173.         // write precompensation
  174.         // delay times are as in WRDELAY_* parameters, vg_wrd width is always 7 clocks
  175.  
  176.         always @(posedge fclk)
  177.         begin
  178.                   sl_sync[1:0] <= {   sl_sync[0],   vg_sl   };
  179.                   sr_sync[1:0] <= {   sr_sync[0],   vg_sr   };
  180.                 tr43_sync[1:0] <= { tr43_sync[0],   vg_tr43 };
  181.                   wd_sync[2:0] <= {   wd_sync[1:0], vg_wd   };
  182.         end
  183.  
  184.         assign   sl =   sl_sync[1]; // just state signals
  185.         assign   sr =   sr_sync[1]; //
  186.         assign tr43 = tr43_sync[1]; //
  187.  
  188.         assign   wd =   wd_sync[1] & (~wd_sync[2]); // strobe: beginning of vg_wd
  189.  
  190.  
  191.         // make delay
  192.         always @(posedge fclk)
  193.         begin
  194.                 if( wd )
  195.                         case( {sl, tr43, sr} )
  196.                         3'b100:  // shift left, outer tracks
  197.                                 wrdelay_cnt <= WRDELAY_OUTER_LEFT;
  198.                         3'b001:  // shift right, outer tracks
  199.                                 wrdelay_cnt <= WRDELAY_OUTER_RIGHT;
  200.                         3'b110:  // shift left, inner tracks
  201.                                 wrdelay_cnt <= WRDELAY_INNER_LEFT;
  202.                         3'b011:  // shift right, inner tracks
  203.                                 wrdelay_cnt <= WRDELAY_INNER_RIGHT;
  204.                         default: // no shift
  205.                                 wrdelay_cnt <= WRDELAY_STANDARD;
  206.                         endcase
  207.                 else if( !delay_end )
  208.                         wrdelay_cnt <= wrdelay_cnt - 4'd1;
  209.         end
  210.  
  211.         assign delay_end = (wrdelay_cnt==4'd0);
  212.  
  213.  
  214.         // make vg_wdr impulse after a delay
  215.  
  216.         always @(posedge fclk)
  217.                 if( wrwidth_ena )
  218.                 begin
  219.                         if( wd )
  220.                                 wrwidth_cnt <= 4'd0;
  221.                         else
  222.                                 wrwidth_cnt <= wrwidth_cnt + 4'd1;
  223.                 end
  224.  
  225.         assign wrwidth_ena = wd | ( delay_end & (~wrwidth_cnt[3]) );
  226.  
  227.         always @(posedge fclk)
  228.                 vg_wrd <= | wrwidth_cnt[2:0]; // only 7 clocks is the lendth of vg_wrd
  229.  
  230.  
  231.  
  232.  
  233.  
  234.         // RCLK/RAWR restore
  235.         // currently simplest counter method, no PLL whatsoever now
  236.         //
  237.         // RCLK period must be 112 clocks (@28 MHz), or 56 clocks for each state
  238.         // RAWR on time is 4 clocks
  239.  
  240.         // digital filter - removing glitches
  241.         always @(posedge fclk)
  242.                 rdat_sync[4:0] <= { rdat_sync[3:0], (~rdat_n) };
  243.  
  244.  
  245.  
  246.         always @(posedge fclk)
  247.         begin
  248.                 if( rdat_sync[4:1]==4'b1111 ) // filter beginning of strobe
  249.                         rdat_edge1 <= 1'b1;
  250.                 else if( rclk_strobe ) // filter any more strobes during same strobe half-perion
  251.                         rdat_edge1 <= 1'b0;
  252. //              else if( rdat_sync[4:1]==4'b0000 )
  253. //                      rdat_edge1 <= 1'b0;
  254.  
  255.                 rdat_edge2 <= rdat_edge1;
  256.         end
  257.  
  258.         assign rdat = rdat_edge1 & (~rdat_edge2);
  259.  
  260. //      assign rdat = rdat_sync[1] & (~rdat_sync[2]);
  261.  
  262.  
  263.  
  264.         always @(posedge fclk)
  265.                 if( rwidth_ena )
  266.                 begin
  267.                         if( rdat )
  268.                                 rwidth_cnt <= 4'd0;
  269.                         else
  270.                                 rwidth_cnt <= rwidth_cnt + 4'd1;
  271.                 end
  272.  
  273.         assign rwidth_ena = rdat | (~rwidth_cnt[2]); // [2] - 140ns, [3] - 280ns
  274.  
  275.  
  276.         assign rclk_strobe = (rclk_cnt==6'd0);
  277.  
  278.         always @(posedge fclk)
  279.         begin
  280.                 if( rdat )
  281.                         rclk_cnt <= 6'd29; // (56/2)-1 plus halfwidth of RAWR
  282.                 else if( rclk_strobe )
  283.                         rclk_cnt <= 6'd55; // period is 56 clocks
  284.                 else
  285.                         rclk_cnt <= rclk_cnt - 6'd1;
  286.         end
  287.  
  288.         reg [5:0] counter = 0;                    
  289.         wire[5:0] delta = 27 - counter;
  290.         wire[5:0] shift = { delta[5], delta[5], delta[4:1] }; // sign div
  291.         wire[5:0] inc   = rawr_sr[1:0] == 2'b10 ? shift : 1;
  292.  
  293.         reg [3:0] rawr_sr;
  294.  
  295.         always @ (posedge fclk)
  296.         begin
  297.                 rawr_sr <= { rawr_sr[2:0], rdat_n };
  298.                 vg_rawr <= !(rawr_sr[3] && !rawr_sr[0] ); // rawr 100ns
  299.         end
  300.  
  301.         always @ (posedge fclk)
  302.         begin              
  303.                 if (counter < 55)
  304.                         counter <= counter + inc;  
  305.                 else          
  306.                 begin            
  307.                         counter <= 0;
  308.                         vg_rclk <= ~vg_rclk;  
  309.                 end    
  310.         end
  311.  
  312.  
  313.  
  314. endmodule
  315.  
  316.