Subversion Repositories tsfmpro

Rev

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

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