Subversion Repositories tsfmpro

Rev

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

  1. // testbench for TurboFMpro rtl
  2. // (c) NedoPC 2018
  3.  
  4. `timescale 1ns/1ps
  5.  
  6.  
  7. `define CLK14_HALFPERIOD (35.000) /* to make it more async */
  8. `define CLK56_HALFPERIOD (8.929)
  9.  
  10. module tb;
  11.  
  12.  
  13.         // board config
  14.         reg [3:0] portcfg = 4'hF;
  15.         // conf[0] - YM curchip select ( 0 - select D0, 1 - select D1, !!!1 after reset!!! )
  16.         // conf[1] - YM stat reg select ( 1 - read register, 0 - read status )
  17.         // conf[2] - YM fm part disable ( 0 - enable, 1 - disable )
  18.         // conf[3] - SAA enable ( 0 - enable, 1 - disable )
  19.         //
  20. //      reg mode_enable_saa  = 1'b1, //0 - saa disabled (board equals to TurboFM)
  21. //          mode_enable_ymfm = 1'b1; //0 - single AY mode (no two AY, no FM, no SAA)
  22.  
  23.         localparam MODE_SINGLE  = 2'b00;
  24.         localparam MODE_TURBOAY = 2'b01;
  25.         localparam MODE_TURBOFM = 2'b10;
  26.         localparam MODE_FULL    = 2'b11;
  27.  
  28.         reg [1:0] mode; // {mode1,mode0}: 00 - single AY, 01 - turbo AY,
  29.                         //                10 - turbo FM,  11 - turbo FM + SAA
  30.  
  31.  
  32.         reg zclk, fclk;
  33.  
  34.         reg rst_n;
  35.  
  36.         wire aybc1,
  37.              aybc2,
  38.              aybdir,
  39.              aya8,
  40.              aya9_n;
  41.  
  42.  
  43.         wire ymclk,
  44.              ymcs1_n,
  45.              ymcs2_n,
  46.              ymrd_n,
  47.              ymwr_n,
  48.              yma0,
  49.              ymop1,
  50.              ymop2,
  51.              ymop1d,
  52.              ymop2d;
  53.  
  54.         wire saaclk,
  55.              saacs_n,
  56.              saawr_n,
  57.              saaa0;
  58.  
  59.  
  60.         wire [7:0] d; // internal YM/SAA bus
  61.  
  62.  
  63.         // cpu simulation
  64.         reg mreq_n,iorq_n,rd_n,wr_n;
  65.         reg  [15:0] zaddr;
  66.         wire [ 7:0] zdata;
  67.         reg  [ 7:0] zdout;
  68.         reg         zdena;
  69.  
  70.  
  71.         // ym test data
  72.         wire [7:0] ym_adr    [0:1];
  73.         wire [7:0] ym_wrdat  [0:1];
  74.         reg  [7:0] ym_rddat  [0:1];
  75.         reg  [7:0] ym_rdstat [0:1];
  76.  
  77.  
  78.  
  79.  
  80.         reg [7:0] ym_reg [0:1] = '{8'hFF,8'hFF};
  81.         reg [7:0] saa_reg = 8'hFF;
  82.  
  83.  
  84.  
  85.  
  86.         // 14MHz clock
  87.         initial
  88.         begin
  89.                 zclk = 1'b0;
  90.  
  91.                 forever #(`CLK14_HALFPERIOD) zclk = ~zclk;
  92.         end
  93.  
  94.         // 28MHz clock
  95.         initial
  96.         begin
  97.                 fclk = 1'b0;
  98.  
  99.                 forever #(`CLK56_HALFPERIOD) fclk = ~fclk;
  100.         end
  101.  
  102.  
  103.  
  104.         // reset
  105.         initial
  106.         begin
  107.                 rst_n = 1'b0;
  108.                 iorq_n = 1'b1;
  109.                 wr_n   = 1'b1;
  110.                 rd_n   = 1'b1;
  111.                 zaddr  = 16'd0;
  112.                 repeat(5) @(posedge fclk);
  113.                 rst_n <= 1'b1;
  114.         end
  115.  
  116.  
  117.  
  118.  
  119.  
  120.         // zdata control
  121.         assign zdata = zdena ? zdout : 8'hZZ;
  122.  
  123.         // ay access control
  124.         ay_access ay_access
  125.         (
  126.                 .a     (zaddr),
  127.                 .iorq_n(iorq_n),
  128.                 .wr_n  (wr_n),
  129.                 .rd_n  (rd_n),
  130.  
  131.                 .bdir(aybdir),
  132.                 .bc1 (aybc1),
  133.                 .bc2 (aybc2),
  134.                 .a8  (aya8),
  135.                 .a9_n(aya9_n)
  136.         );
  137.  
  138.         // saa accesses check
  139.         saa_checker saa_checker
  140.         (
  141.                 .cs_n(saacs_n),
  142.                 .wr_n(saawr_n),
  143.                 .a0(saaa0),
  144.                 .d(d)
  145.         );
  146.  
  147.         // ym access checkers
  148.         ym_checker ym1
  149.         (
  150.                 .cs_n(ymcs1_n),
  151.                 .rd_n(ymrd_n),
  152.                 .wr_n(ymwr_n),
  153.                 .a0  (yma0),
  154.                 .d   (d),
  155.  
  156.                 .rddat (ym_rddat [0]),
  157.                 .rdstat(ym_rdstat[0]),
  158.                 .adr   (ym_adr   [0]),
  159.                 .wrdat (ym_wrdat [0])
  160.         );
  161.         //     
  162.         ym_checker ym2
  163.         (
  164.                 .cs_n(ymcs2_n),
  165.                 .rd_n(ymrd_n),
  166.                 .wr_n(ymwr_n),
  167.                 .a0  (yma0),
  168.                 .d   (d),
  169.  
  170.                 .rddat (ym_rddat [1]),
  171.                 .rdstat(ym_rdstat[1]),
  172.                 .adr   (ym_adr   [1]),
  173.                 .wrdat (ym_wrdat [1])
  174.         );
  175.  
  176.  
  177.  
  178.  
  179.  
  180.         // DUT connection
  181.         top DUT
  182.         (
  183.                 .fclk(fclk),
  184.                
  185.                 .ayd(zdata),
  186.                 .d  (d),
  187.        
  188.                 .ayres_n(rst_n),
  189.                 .aybc1  (aybc1  ),
  190.                 .aybc2  (aybc2  ),
  191.                 .aybdir (aybdir ),
  192.                 .aya8   (aya8   ),
  193.                 .aya9_n (aya9_n ),
  194.        
  195.                 .mode0(mode[0]),
  196.                 .mode1(mode[1]),
  197.                
  198.                 .ymclk  (ymclk  ),
  199.                 .ymcs1_n(ymcs1_n),
  200.                 .ymcs2_n(ymcs2_n),
  201.                 .ymrd_n (ymrd_n ),
  202.                 .ymwr_n (ymwr_n ),
  203.                 .yma0   (yma0   ),
  204.                 .ymop1  (ymop1  ),
  205.                 .ymop2  (ymop2  ),
  206.                 .ymop1d (ymop1d ),
  207.                 .ymop2d (ymop2d ),
  208.        
  209.                 .saaclk (saaclk ),
  210.                 .saacs_n(saacs_n),
  211.                 .saawr_n(saawr_n),
  212.                 .saaa0  (saaa0  )
  213.         );
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221.  
  222.  
  223.  
  224.  
  225.         // test script
  226.         initial
  227.         begin
  228.                 wait(rst_n===1'b1);
  229.                 repeat(5) @(posedge zclk);
  230.  
  231.  
  232.                 wr_num(8'hFF); // initialization of regnum
  233.  
  234.  
  235.                 forever
  236.                 begin
  237.                         repeat(5) @(posedge zclk);
  238.                                 mode[1:0] = $random()>>30;
  239.                         repeat(5) @(posedge zclk);
  240.  
  241.                         do_rnd_test(1000);
  242.                 end
  243.  
  244.  
  245.        
  246.  
  247.  
  248.  
  249. /*
  250.                 wr_num(8'hF7);
  251.                 test_saa_write();
  252.  
  253.                 wr_num(8'hfe);
  254.                 test_ym_write(0);
  255.                 test_ym_read(0,1);
  256.  
  257.                 wr_num(8'hfc);
  258.                 test_ym_write(0);
  259.                 test_ym_read(0,0);
  260.  
  261.                 wr_num(8'hff);
  262.                 test_ym_write(1);
  263.                 test_ym_read(1,1);
  264.  
  265.                 wr_num(8'hfd);
  266.                 test_ym_write(1);
  267.                 test_ym_read(1,0);
  268.  
  269.                 $display("finished!");
  270.                 $stop();
  271. */
  272.         end
  273.  
  274.  
  275.  
  276.  
  277.  
  278.  
  279.  
  280.         task do_rnd_test;
  281.                 input int iterations;
  282.  
  283.                 reg [7:0] rdt;
  284.  
  285.                 repeat(iterations)
  286.                 begin
  287.  
  288.                         if( $random()>32'hF000_0000 )
  289.                                 wr_num( $random()>>24 );
  290.                         else if( $random()>>31 )
  291.                         begin
  292.                                 wr_dat( $random()>>24 );
  293.                         end
  294.                         else
  295.                         begin
  296.                                 rd_dat();
  297.                         end
  298.                 end
  299.  
  300.         endtask
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320. ////////////////////////////////////////////////////////////////////////////////
  321.  
  322.  
  323.         // tasks for bffd/fffd port control
  324.         task wr_num;
  325.                 input [7:0] num;
  326.                 iowr(16'hFFFD,num);
  327.  
  328.                 if( num>=8'hF0 )
  329.                         portcfg = num[3:0];
  330.                 else if( !portcfg[3] && mode==MODE_FULL )
  331.                         saa_reg = num;
  332.                 else if( mode>=MODE_TURBOAY && !portcfg[0] )
  333.                         ym_reg[0] = num;
  334.                 else
  335.                         ym_reg[1] = num;
  336.         endtask
  337.  
  338.  
  339.  
  340.  
  341.         task wr_dat;
  342.                 input [7:0] dat;
  343.  
  344.                 int chipn;
  345.  
  346.  
  347.                 iowr(16'hBFFD,dat);
  348.  
  349.                 // see whoch chip has been written
  350.                 if( !portcfg[3] && mode==MODE_FULL )
  351.                 begin // check SAA write
  352.                         if( saa_checker.adr!==saa_reg ||
  353.                             saa_checker.dat!==dat     )
  354.                         begin
  355.                                 $display("%m: SAA write reg failed!");
  356.                                 $stop;
  357.                         end
  358.                 end
  359.                 else
  360.                 begin
  361.                         chipn=1;
  362.                         if( mode>=MODE_TURBOAY && !portcfg[0] ) chipn=0;
  363.  
  364.                         if( ym_adr  [chipn]!==ym_reg[chipn] ||
  365.                             ym_wrdat[chipn]!==dat           )
  366.                         begin
  367.                                 $display("%m: YM %d write reg failed!",chipn);
  368.                                 $stop;
  369.                         end
  370.                 end
  371.  
  372.         endtask
  373.  
  374.  
  375.  
  376.  
  377.         task rd_dat;
  378.  
  379.                 reg [7:0] dat;
  380.  
  381.                 int chipn;
  382.                 int statr;
  383.  
  384.                 ym_rddat[0] = $random()>>24;
  385.                 ym_rddat[1] = $random()>>24;
  386.                 ym_rdstat[0] = $random()>>24;
  387.                 ym_rdstat[1] = $random()>>24;
  388.  
  389.                 iord(16'hFFFD,dat);
  390.  
  391.  
  392.                 if( !portcfg[3] && mode==MODE_FULL )
  393.                 begin
  394.                         // nothing to do, can't read from SAA1099
  395.                 end
  396.                 else
  397.                 begin
  398.                         chipn = 1;
  399.                         statr = 0;
  400.                
  401.                         if( mode==MODE_SINGLE )
  402.                         begin // single ay only
  403.                                 chipn=1;
  404.                                 statr=0;
  405.                         end
  406.                         else if( mode==MODE_TURBOAY )
  407.                         begin
  408.                                 chipn = portcfg[0];
  409.                                 statr = 0;
  410.                         end
  411.                         else // mode>=MODE_TURBOFM
  412.                         begin
  413.                                 chipn = portcfg[0];
  414.                                 statr = !portcfg[1] && !portcfg[2];
  415.                         end
  416.  
  417.                         if( ym_adr[chipn]!==ym_reg[chipn] || dat!==(statr ? ym_rdstat[chipn] : ym_rddat[chipn]) )
  418.                         begin
  419.                                 $display("%m: YM %d read reg failed!",chipn);
  420.                                 $stop;
  421.                         end
  422.  
  423.  
  424.                 end
  425.  
  426.         endtask
  427.  
  428.  
  429.  
  430.  
  431.  
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.         // tasks for z80 bus model (simplified)
  439.         task iord;
  440.  
  441.                 input [15:0] addr;
  442.  
  443.                 output [7:0] data;
  444.  
  445.                 begin
  446.  
  447.                         @(posedge zclk);
  448.  
  449.                         mreq_n <= 1'b1;
  450.                         iorq_n <= 1'b1;
  451.                         rd_n   <= 1'b1;
  452.                         wr_n   <= 1'b1;
  453.  
  454.                         zdena  <= 1'b0;
  455.  
  456.                         zaddr <= addr;
  457.  
  458.                         @(posedge zclk);
  459.  
  460.                         iorq_n <= 1'b0;
  461.                         rd_n   <= 1'b0;
  462.  
  463.                         @(posedge zclk);
  464.                         @(posedge zclk);
  465.                         @(negedge zclk);
  466.  
  467.                         data = zdata;
  468.  
  469.                         iorq_n <= 1'b1;
  470.                         rd_n   <= 1'b1;
  471.                 end
  472.  
  473.         endtask
  474.  
  475.  
  476.         task iowr;
  477.  
  478.                 input [15:0] addr;
  479.                 input [ 7:0] data;
  480.  
  481.                 begin
  482.  
  483.                         @(posedge zclk);
  484.  
  485.                         mreq_n <= 1'b1;
  486.                         iorq_n <= 1'b1;
  487.                         rd_n   <= 1'b1;
  488.                         wr_n   <= 1'b1;
  489.  
  490.                         zaddr <= addr;
  491.                        
  492.                         @(negedge zclk);
  493.                         zdena  <= 1'b1;
  494.                         zdout <= data;
  495.  
  496.                         @(posedge zclk);
  497.  
  498.                         iorq_n <= 1'b0;
  499.                         wr_n   <= 1'b0;
  500.  
  501.                         @(posedge zclk);
  502.                         @(posedge zclk);
  503.                         @(negedge zclk);
  504.  
  505.                         iorq_n <= 1'b1;
  506.                         wr_n   <= 1'b1;
  507.  
  508.                         wait(wr_n==1'b1); // delta-cycle delay!!!
  509.                         zdena  <= 1'b0;
  510.                 end
  511.  
  512.         endtask
  513.  
  514.  
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521.  
  522.  
  523.  
  524.  
  525.  
  526.  
  527.  
  528.  
  529.         // tasks for saa testing
  530.         task test_saa_write;
  531.                 reg [7:0] adr;
  532.                 reg [7:0] dat;
  533.         begin
  534.  
  535.                 adr = $random();
  536.                 dat = $random();
  537.  
  538.                 wr_num(adr);
  539.                 wr_dat(dat);
  540.  
  541.                 #(1);
  542.  
  543.                 if( adr!==saa_checker.adr )
  544.                 begin
  545.                         $display("test_saa_write: address write failed!");
  546.                         $stop;
  547.                 end
  548.  
  549.                 if( dat!==saa_checker.dat )
  550.                 begin
  551.                         $display("test_saa_write: data write failed!");
  552.                         $stop;
  553.                 end
  554.         end
  555.         endtask
  556.  
  557.         // tasks for ym testing
  558.         task test_ym_write;
  559.                 input integer ymnum;
  560.         begin : test_ym_write
  561.                 reg [7:0] adr, dat;
  562.                 adr = $random();
  563.                 dat = $random();
  564.  
  565.                 wr_num(adr);
  566.                 wr_dat(dat);
  567.  
  568.                 #(1.0);
  569.  
  570.                 if( adr!==ym_adr[ymnum] )
  571.                 begin
  572.                         $display("test_ym_write: chip %d, address write failed!",ymnum);
  573.                         $stop;
  574.                 end
  575.  
  576.                 if( dat!==ym_wrdat[ymnum] )
  577.                 begin
  578.                         $display("test_ym_write: chip %d, data write failed!",ymnum);
  579.                         $stop;
  580.                 end
  581.         end
  582.         endtask
  583.  
  584.         task test_ym_read;
  585.                 input integer ymnum;
  586.                 input integer addr;
  587.         begin
  588.         end
  589.         endtask
  590.  
  591. endmodule
  592.  
  593.  
  594.  
  595.  
  596. // bdir/bc1/bc2/a8/a9 decoder
  597. module ay_access
  598. (
  599.         input  wire [15:0] a,
  600.         input  wire        iorq_n,
  601.         input  wire        wr_n,
  602.         input  wire        rd_n,
  603.  
  604.         output wire        bdir,
  605.         output wire        bc1,
  606.         output wire        bc2,
  607.         output wire        a8,
  608.         output wire        a9_n
  609. );
  610.         reg bdir_r;
  611.         reg bc1_r;
  612.  
  613.         // no testing bc2/a8/a9_n accesses, to the default values
  614.         assign bc2  = 1'b1;
  615.         assign a8   = 1'b1;
  616.         assign a9_n = 1'b0;
  617.  
  618.         // TODO: add different bc2 AND a8/a9_n combinations!
  619.  
  620.         always @*
  621.         begin
  622.                 if     ( !iorq_n && !wr_n && !a[1] &&  a[14] ) // wr FFFD
  623.                         {bdir_r,bc1_r} = 2'b11;
  624.                 else if( !iorq_n && !wr_n && !a[1] && !a[14] ) // wr BFFD
  625.                         {bdir_r,bc1_r} = 2'b10;
  626.                 else if( !iorq_n && !rd_n && !a[1] &&  a[14] ) // rd FFFD
  627.                         {bdir_r,bc1_r} = 2'b01;
  628.                 else // idle
  629.                         {bdir_r,bc1_r} = 2'b00;
  630.         end
  631.  
  632.         assign bdir = bdir_r;
  633.         assign bc1  = bc1_r;
  634.  
  635. endmodule
  636.  
  637.  
  638.  
  639. module saa_checker
  640. (
  641.         input  wire cs_n,
  642.         input  wire wr_n,
  643.         input  wire a0,
  644.         input  wire [7:0] d
  645. );
  646.         reg [7:0] adr = 8'hFF;
  647.         reg [7:0] dat;
  648.  
  649.         reg int_a0;
  650.  
  651.         always @(a0) int_a0 = #(0.1) a0;
  652.  
  653.         wire stb_n = cs_n | wr_n;
  654.  
  655.         always @(negedge stb_n)
  656.         begin
  657.                 #0.2;
  658.                 if( int_a0==0 ) dat <= d;
  659.                 if( int_a0==1 ) adr <= d;
  660.         end
  661.  
  662. endmodule
  663.  
  664. module ym_checker
  665. (
  666.         input  wire cs_n,
  667.         input  wire rd_n,
  668.         input  wire wr_n,
  669.         input  wire a0,
  670.         inout  wire [7:0] d,
  671.  
  672.         input  wire [7:0] rddat,
  673.         input  wire [7:0] rdstat,
  674.         output wire [7:0] adr,
  675.         output reg  [7:0] wrdat
  676. );
  677.  
  678.         reg [7:0] int_adr = 8'hFF;
  679.         assign adr=int_adr;
  680.  
  681.  
  682.         reg int_a0;
  683.  
  684.         wire wr_stb_n = cs_n | wr_n;
  685.  
  686.         initial int_a0 = a0;
  687.         always @(a0) int_a0 = #(0.1) a0;
  688.  
  689.         always @(negedge wr_stb_n)
  690.         begin
  691.                 #0.2;
  692.                 if( int_a0==1'b0 ) int_adr <= d;
  693.                 if( int_a0==1'b1 ) wrdat <= d;
  694.         end
  695.  
  696.         assign d = (cs_n|rd_n) ? 8'hZZ : (int_a0 ? rddat : rdstat);
  697.  
  698. endmodule
  699.  
  700.