Subversion Repositories pentevo

Rev

Rev 668 | 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. // DRAM arbiter. Shares DRAM between processor and video data fetcher
  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.  
  25. // 14.06.2011:
  26. // removed cpu_stall and cpu_waitcyc.
  27. // changed cpu_strobe behavior (only strobes read data arrival now).
  28. // added cpu_next signal (shows whether next DRAM cycle CAN be grabbed by CPU)
  29. //
  30. // Now it is a REQUIREMENT for 'go' signal only starting and ending on
  31. // beginning of DRAM cycle (i.e. right after 'cend' strobe).
  32.  
  33.  
  34. // 13.06.2011:
  35. // Придётся потребовать, чтоб go устанавливался сразу после cend (у меня [lvd] это так).
  36. // это для того, чтобы процессор на 14мгц мог заранее и в любой момент знать, на
  37. // сколько завейтиться. Вместо cpu_ack введем другой сигнал, который в течение всего
  38. // драм-цикла будет показывать, чей может быть следующий цикл - процессора или только
  39. // видео. По сути это и будет также cpu_ack, но валидный в момент cpu_req (т.е.
  40. // в момент cend) и ранее.
  41.  
  42. // 12.06.2011:
  43. // проблема: если цпу просит цикл чтения, а его дать не могут,
  44. // то он должен держать cpu_req. однако, снять он его может
  45. // только по cpu_strobe, при этом также отправится еще один
  46. // запрос чтения!!!
  47. // решение: добавить сигнал cpu_ack, по которому узнаётся, что
  48. // арбитр зохавал запрос (записи или чтения), который будет
  49. // совпадать с нынешним cpu_strobe на записи (cbeg), а будущий
  50. // cpu_strobe сделать только как строб данных на зохаванном
  51. // запросе чтеня.
  52. // это, возможно, позволит удалить всякие cpu_waitcyc...
  53.  
  54.  
  55. // Arbitration is made on full 8-cycle access blocks. Each cycle is defined by dram.v and consists of 4 fpga clocks.
  56. // During each access block, there can be either no videodata access, 1 videodata access, 2, 4 or full 8 accesses.
  57. // All spare cycles can be used by processor. If nobody uses memory in the given cycle, refresh cycle is performed
  58. //
  59. // In each access block, videodata accesses are spreaded all over the block so that processor receives cycle
  60. // as fast as possible, until there is absolute need to fetch remaining video data
  61. //
  62. // Examples:
  63. //
  64. // |                 access block                  | 4 video accesses during block, no processor accesses. video accesses are done
  65. // | vid | vid | vid | vid | ref | ref | ref | ref | as soon as possible, spare cycles are refresh ones
  66. //
  67. // |                 access block                  | 4 video accesses during block, processor requests access every other cycle
  68. // | vid | prc | vid | prc | vid | prc | vid | prc |
  69. //
  70. // |                 access block                  | 4 video accesses, processor begins requesting cycles continously from second one
  71. // | vid | prc | prc | prc | prc | vid | vid | vid | so it is given cycles while there is such possibility. after that processor
  72. //                                                   can't access mem until the end of access block and stalls
  73. //
  74. // |                 access block                  | 8 video accesses, processor stalls, if it is requesting cycles
  75. // | vid | vid | vid | vid | vid | vid | vid | vid |
  76. //
  77. // |                 access block                  | 2 video accesses, single processor request, other cycles are refresh ones
  78. // | vid | vid | ref | ref | cpu | ref | ref | ref |
  79. //
  80. // |                 access block                  | 4 video accesses, single processor request, other cycles are refresh ones
  81. // | vid | vid | cpu | vid | vid | ref | ref | ref |
  82. //
  83. // access block begins at any dram cycle, then blocks go back-to-back
  84. //
  85. // key signals are go and cpu_req, sampled at the end of each dram cycle. Must be set to the module
  86. // one clock cycle earlier the clock of the beginning current dram cycle
  87.  
  88. `include "../include/tune.v"
  89.  
  90. module arbiter(
  91.  
  92.         input clk,
  93.         input rst_n,
  94.  
  95.         // dram.v interface
  96.         output     [20:0] dram_addr,   // address for dram access
  97.         output reg        dram_req,    // dram request
  98.         output reg        dram_rnw,    // Read-NotWrite
  99.         input             dram_cbeg,   // cycle begin
  100.         input             dram_rrdy,   // read data ready (coincides with cend)
  101.         output      [1:0] dram_bsel,   // positive bytes select: bsel[1] for wrdata[15:8], bsel[0] for wrdata[7:0]
  102.         input      [15:0] dram_rddata, // data just read
  103.         output     [15:0] dram_wrdata, // data to be written
  104.  
  105.  
  106.         output reg cend,      // regenerates this signal: end of DRAM cycle. cend is one-cycle positive pulse just before cbeg pulse
  107.         output reg pre_cend,  // one clock earlier cend
  108.         output reg post_cbeg, // one more earlier
  109.  
  110.  
  111.         input go, // start video access blocks
  112.  
  113.         input [1:0] bw, // required bandwidth: 3'b00 - 1 video cycle per block
  114.                         //                     3'b01 - 2 video accesses
  115.                         //                     3'b10 - 4 video accesses
  116.                         //                     3'b11 - 8 video accesses (stall of CPU)
  117.  
  118.         input  [20:0] video_addr,   // during access block, only when video_strobe==1
  119.         output [15:0] video_data,   // read video data which is valid only during video_strobe==1 because video_data
  120.                                     // is just wires to the dram.v's rddata signals
  121.         output reg    video_strobe, // positive one-cycle strobe as soon as there is next video_data available.
  122.                                     // if there is video_strobe, it coincides with cend signal
  123.         output reg    video_next,   // on this signal you can change video_addr; it is one clock leading the video_strobe
  124.  
  125.  
  126.  
  127.         input  wire        cpu_req,
  128.         input  wire        cpu_rnw,
  129.         input  wire [20:0] cpu_addr,
  130.         input  wire [ 7:0] cpu_wrdata,
  131.         input  wire        cpu_wrbsel,
  132.  
  133.         output wire [15:0] cpu_rddata,
  134.         output reg         cpu_next,
  135.         output reg         cpu_strobe
  136. );
  137.  
  138.         wire cbeg;
  139.  
  140.         reg [1:0] cctr; // DRAM cycle counter: 0 when cbeg is 1, then 1,2,3,0, etc...
  141.  
  142.  
  143.         reg stall;
  144.         reg cpu_rnw_r;
  145.  
  146.         reg [2:0] blk_rem;  // remaining accesses in a block (7..0)
  147.         reg [2:0] blk_nrem; // remaining for the next dram cycle
  148.  
  149.         reg [2:0] vid_rem;  // remaining video accesses in block (4..0)
  150.         reg [2:0] vid_nrem; // for rhe next cycle
  151.  
  152.  
  153.         wire [2:0] vidmax; // max number of video cycles in a block, depends on bw input
  154.  
  155.  
  156.  
  157.         localparam CYC_VIDEO = 2'b00; // do             there
  158.         localparam CYC_CPU   = 2'b01; //   not     since     are   dependencies
  159.         localparam CYC_FREE  = 2'b10; //      alter             bit
  160.  
  161.         reg [1:0] curr_cycle; // type of the cycle in progress
  162.         reg [1:0] next_cycle; // type of the next cycle
  163.  
  164.  
  165.  
  166.  
  167.  
  168.         initial // simulation only!
  169.         begin
  170.                 curr_cycle = CYC_FREE;
  171.                 blk_rem = 0;
  172.                 vid_rem = 0;
  173.         end
  174.  
  175.  
  176.  
  177.  
  178.         assign cbeg = dram_cbeg; // just alias
  179.  
  180.         // make cycle strobe signals
  181.         always @(posedge clk)
  182.         begin
  183.                 post_cbeg <= cbeg;
  184.                 pre_cend  <= post_cbeg;
  185.                 cend      <= pre_cend;
  186.         end
  187.  
  188.  
  189.         // track blk_rem counter: how many cycles left to the end of block (7..0)
  190.         always @(posedge clk) if( cend )
  191.         begin
  192.                 blk_rem <= blk_nrem;
  193.  
  194.                 if( (blk_rem==3'd0) )
  195.                         stall <= (bw==2'd3) & go;
  196.         end
  197.  
  198.         always @*
  199.         begin
  200.                 if( (blk_rem==3'd0) && go )
  201.                         blk_nrem = 7;
  202.                 else
  203.                         blk_nrem = (blk_rem==0) ? 3'd0 : (blk_rem-3'd1);
  204.         end
  205.  
  206.  
  207.  
  208.         // track vid_rem counter
  209.         assign vidmax = (3'b001) << bw; // 1,2,4 or 8 - just to know how many cycles to perform
  210.  
  211.         always @(posedge clk) if( cend )
  212.         begin
  213.                 vid_rem <= vid_nrem;
  214.         end
  215.  
  216.         always @*
  217.         begin
  218.                 if( go && (blk_rem==3'd0) )
  219.                         vid_nrem = cpu_req ? vidmax : (vidmax-3'd1);
  220.                 else
  221.                         if( next_cycle==CYC_VIDEO )
  222.                                 vid_nrem = (vid_rem==3'd0) ? 3'd0 : (vid_rem-3'd1);
  223.                         else
  224.                                 vid_nrem = vid_rem;
  225.         end
  226.  
  227.  
  228.  
  229.  
  230.         // next cycle decision
  231.         always @*
  232.         begin
  233.                 if( blk_rem==3'd0 )
  234.                 begin
  235.                         if( go )
  236.                         begin
  237.                                 if( bw==2'b11 )
  238.                                 begin
  239.                                         cpu_next = 1'b0;
  240.  
  241.                                         next_cycle = CYC_VIDEO;
  242.                                 end
  243.                                 else
  244.                                 begin
  245.                                         cpu_next = 1'b1;
  246.  
  247.                                         if( cpu_req )
  248.                                                 next_cycle = CYC_CPU;
  249.                                         else
  250.                                                 next_cycle = CYC_VIDEO;
  251.                                 end
  252.                         end
  253.                         else // !go
  254.                         begin
  255.                                 cpu_next = 1'b1;
  256.  
  257.                                 if( cpu_req )
  258.                                         next_cycle = CYC_CPU;
  259.                                 else
  260.                                         next_cycle = CYC_FREE;
  261.                         end
  262.                 end
  263.                 else // blk_rem!=3'd0
  264.                 begin
  265.                         if( stall )
  266.                         begin
  267.                                 cpu_next = 1'b0;
  268.  
  269.                                 next_cycle = CYC_VIDEO;
  270.                         end
  271.                         else
  272.                         begin
  273.                                 if( vid_rem==blk_rem )
  274.                                 begin
  275.                                         cpu_next = 1'b0;
  276.        
  277.                                         next_cycle = CYC_VIDEO;
  278.                                 end
  279.                                 else
  280.                                 begin
  281.                                         cpu_next = 1'b1;
  282.        
  283.                                         if( cpu_req )
  284.                                                 next_cycle = CYC_CPU;
  285.                                         else
  286.                                                 if( vid_rem==3'd0 )
  287.                                                         next_cycle = CYC_FREE;
  288.                                                 else
  289.                                                         next_cycle = CYC_VIDEO;
  290.                                 end
  291.                         end
  292.                 end
  293.         end
  294.  
  295.  
  296.  
  297.  
  298.         // just current cycle register
  299.         always @(posedge clk) if( cend )
  300.         begin
  301.                 curr_cycle <= next_cycle;
  302.         end
  303.  
  304.  
  305.  
  306.  
  307.         // route required data/etc. to and from the dram.v
  308.  
  309.         assign dram_wrdata[15:0] = { cpu_wrdata[7:0], cpu_wrdata[7:0] };
  310.         assign dram_bsel[1:0] = { ~cpu_wrbsel, cpu_wrbsel };
  311.  
  312.         assign dram_addr = next_cycle[0] ? cpu_addr : video_addr;
  313.  
  314.         assign cpu_rddata = dram_rddata;
  315.         assign video_data = dram_rddata;
  316.  
  317.         always @*
  318.         begin
  319.                 if( next_cycle[1] ) // CYC_FREE
  320.                 begin
  321.                         dram_req = 1'b0;
  322.                         dram_rnw = 1'b1;
  323.                 end
  324.                 else // CYC_CPU or CYC_VIDEO
  325.                 begin
  326.                         dram_req = 1'b1;
  327.                         if( next_cycle[0] ) // CYC_CPU
  328.                                 dram_rnw = cpu_rnw;
  329.                         else // CYC_VIDEO
  330.                                 dram_rnw = 1'b1;
  331.                 end
  332.         end
  333.  
  334.  
  335.  
  336.         // generation of read strobes: for video and cpu
  337.  
  338.  
  339.         always @(posedge clk)
  340.         if( cend )
  341.                 cpu_rnw_r <= cpu_rnw;
  342.  
  343.  
  344.         always @(posedge clk)
  345.         begin
  346.                 if( (curr_cycle==CYC_CPU) && cpu_rnw_r && pre_cend )
  347.                         cpu_strobe <= 1'b1;
  348.                 else
  349.                         cpu_strobe <= 1'b0;
  350.         end
  351.  
  352.  
  353.         always @(posedge clk)
  354.         begin
  355.                 if( (curr_cycle==CYC_VIDEO) && pre_cend )
  356.                         video_strobe <= 1'b1;
  357.                 else
  358.                         video_strobe <= 1'b0;
  359.  
  360.                 if( (curr_cycle==CYC_VIDEO) && post_cbeg )
  361.                         video_next <= 1'b1;
  362.                 else
  363.                         video_next <= 1'b0;
  364.         end
  365.  
  366.  
  367.  
  368. endmodule
  369.  
  370.