Top secrets sources NedoPC ngs

Rev

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

// testbench for CPLD_buf.v
// (c) NedoPC 2010

`timescale 1ns/1ps


`define CLK20_HALFPERIOD (25.000)
`define CLK24_HALFPERIOD (20.833)


module tb;


        integer seed;


        reg [ 7:0] dummy8;



        reg clk24,clk20;
        reg [1:0] clksel;
        wire clkout;

        reg clkin;

        reg coldres_n;
        wire warmres_n;


        tri1 config_n;
        wire cs;
        reg status_n,conf_done,init_done;



        reg  [15:0] zaddr;
        trireg [ 7:0] zdata;
        reg  [ 7:0] zdout;
        reg         zdena;


        tri1 [ 7:0] mdata;

        wire ma6,ma7,ma10,ma11,ma12,ma13;



        reg in_ramcs0_n,
            in_ramcs1_n,
            in_ramcs2_n,
            in_ramcs3_n;


        reg mreq_n, iorq_n, rd_n, wr_n;

        wire ra6,ra7,ra10,ra11,ra12,ra13;
        wire mema14,mema15,mema19;
        wire memoe_n,memwe_n,romcs_n;
        wire out_ramcs0_n,out_ramcs1_n;



        reg [7:0] romd;
        reg romd_ena;

        reg [7:0] last_mem_data;





        reg [7:0] md;
        reg md_ena;






        reg       memop_type;
        reg [1:0] memop_page;
        reg [7:0] memop_data;

        localparam READ  = 1'b0;
        localparam WRITE = 1'b1;





        // see whether out_ramcs1_n or mema19 will toggle when they shouldn't
        reg ramcs1_toggled;
        reg mema19_toggled;
        reg clr_mema19_ramcs1_toggle;


        // external drive on romcs_n, memoe_n, memwe_n
        reg eromcs_n, ememoe_n, ememwe_n;
        reg edrv;





        reg cold_reset_set;
















        // 20MHz clock
        initial
        begin
                clk20 = 1'b0;

                forever #(`CLK20_HALFPERIOD) clk20 = ~clk20;
        end

        // 24MHz clock
        initial
        begin
                clk24 = 1'b0;

                forever #(`CLK24_HALFPERIOD) clk24 = ~clk24;
        end


        // 10 MHz clock
        initial
        begin
                clkin = 1'b0;

                repeat(2)
                begin
                        @(posedge clk20);
                        @(posedge clk24);
                end

                forever #(2*`CLK20_HALFPERIOD) clkin = ~clkin;
        end


        // cold reset
        initial
        begin
                coldres_n = 1'b0;

                repeat(5) @(posedge clkin);

                coldres_n <= 1'b1;

        end

        // clk switch signals
        initial
        begin
                clksel = 2'b00;

                forever
                begin
                        repeat(10) @(posedge clkout);

                        clksel[1:0] <= $random>>30;
                end
        end

        // control minimal period of switched clock
        real old_time,cur_time;
        integer width,min_width;

        initial
        begin
                old_time=$time;
                cur_time=old_time;
                min_width=1e10;

                #(20); // wait to skip x->value init at the beginning

                forever
                begin
                        @(clkout);

                        cur_time=$realtime;
                        width = 1000.0*(cur_time-old_time);
                        old_time=cur_time;

                        if( width<min_width )
                        begin
                                min_width = width;
                                $display("at time %t,",cur_time);
                                $display("minimum width set to %d",min_width);
                        end
                end
        end


        // status_n, *_done control
        initial
                status_n = 1'b1;
        always @(config_n)
        begin
                status_n <= #1000 config_n;
        end

        initial
                conf_done = 1'b0;

        initial
                init_done = 1'b0;


        // init in_ramcsX_n
        initial
        begin
                in_ramcs0_n = 1'b1;
                in_ramcs1_n = 1'b1;
                in_ramcs2_n = 1'b1;
                in_ramcs3_n = 1'b1;
        end

        // external drive init
        initial
        begin
                eromcs_n = 1'b1;
                ememoe_n = 1'b1;
                ememwe_n = 1'b1;
                edrv     = 1'b0;
        end


        // Z80 cycles
        assign zdata = zdena ? zdout : ( romd_ena ? romd : 8'hZZ);
        //
        initial
        begin
                zdena = 1'b0;

                iorq_n = 1'b1;
                mreq_n = 1'b1;
                rd_n   = 1'b1;
                wr_n   = 1'b1;

                zaddr  = 16'h0000;


                cold_reset_set = 1'b1;


                wait(warmres_n===1'b0);
                wait(warmres_n===1'bZ);
                repeat(3) @(posedge clkin);


                repeat(32)
                begin
                        mema19_toggled = 1'b0;
                        ramcs1_toggled = 1'b0;

                        init_done = 1'b0;


                        test_config_status;

                        test_cold_reset_flag(cold_reset_set);
                        cold_reset_set = 1'b0;

                        test_fpga_cs;

                        test_conf_done;


                        repeat(10) @(posedge clkin);

                        test_rommap;


                        repeat(10) @(posedge clkin);

                        test_rammap;


                        repeat(10) @(posedge clkin);

                        test_cpldoff;


                        test_ramcs_fpga;


                        repeat(10) @(posedge clkin);

                        test_fwd_fpga;


                        repeat(10) @(posedge clkin);

                        test_restart;
                end



                repeat(4) $display("");

                $display("full SUCCESS!");

                $stop;



        end




























        // module connection

        GS_cpld DUT( .clk24in(clk24),
                     .clk20in(clk20),
                     .clksel0(clksel[0]),
                     .clksel1(clksel[1]),
                     .clkout(clkout),

                     .clkin(clkin),
                     .coldres_n(coldres_n),
                     .warmres_n(warmres_n),

                     .config_n(config_n),
                     .status_n(status_n),
                     .conf_done(conf_done),
                     .init_done(init_done),
                     .cs(cs),

                     .mreq_n(mreq_n),
                     .iorq_n(iorq_n),
                     .rd_n(rd_n),
                     .wr_n(wr_n),

                     .d(zdata),
                     .a6 (zaddr[ 6]), .a7 (zaddr[ 7]), .a10(zaddr[10]), .a11(zaddr[11]),
                     .a12(zaddr[12]), .a13(zaddr[13]), .a14(zaddr[14]), .a15(zaddr[15]),

                     .memoe_n(memoe_n),
                     .memwe_n(memwe_n),
                     .romcs_n(romcs_n),

                     .mema14(mema14), .mema15(mema15), .mema19(mema19),

                     .in_ramcs0_n(in_ramcs0_n),
                     .in_ramcs1_n(in_ramcs1_n),
                     .in_ramcs2_n(in_ramcs2_n),
                     .in_ramcs3_n(in_ramcs3_n),

                     .out_ramcs0_n(out_ramcs0_n),
                     .out_ramcs1_n(out_ramcs1_n),

                     .rd(mdata),
                     .ra6 (ma6 ), .ra7 (ma7 ), .ra10(ma10),
                     .ra11(ma11), .ra12(ma12), .ra13(ma13)

               );


        // data passing d<>rd check
        reg old_mreq_n, old_iorq_n, old_memwe_n, old_memoe_n;
        wire ramcs_n = out_ramcs0_n & out_ramcs1_n;
        //
        always @(posedge clkin)
        begin
                old_mreq_n  <= mreq_n;
                old_iorq_n  <= iorq_n;
                old_memwe_n <= memwe_n;
                old_memoe_n <= memoe_n;
        end
        //
        always @(posedge clkin)
        if( !ramcs_n && !memwe_n && !old_memwe_n )
        begin
                if( mdata!==zdata )
                begin
                        $display("error: data do not pass from d to rd!");
                        $stop;
                end
        end
        //
        always @(posedge clkin)
        if( !ramcs_n && !memoe_n && !old_memoe_n )
        begin
                if( mdata!==zdata )
                begin
                        $display("error: data do not pass from rd to d!");
                        $stop;
                end
        end

        // data passing a -> ra check
        always @(posedge clkin)
        if( (!mreq_n && !old_mreq_n) || (!iorq_n && !old_iorq_n) )
        begin
                if( { zaddr[13:10], zaddr[7:6] } !== { ma13,ma12,ma11,ma10,ma7,ma6 } )
                begin
                        $display("error: addresses do not pass from a to ra!");
                        $stop ;
                end
        end


        // RAM and ROM emulators
    //
        always @*
        begin
                if( !memoe_n && ( !out_ramcs0_n || !out_ramcs1_n ) ) // RAM via buffers
                begin
                        seed = $random( {out_ramcs0_n, out_ramcs1_n, mema19, mema15, mema14, ma13, ma12, ma11, ma10, ma7, ma6} );
                        seed = $random;
                        last_mem_data = $random>>24;
                        md = last_mem_data;
                        md_ena = 1'b1;
                end
                else
                        md_ena = 1'b0;
        end
        //
        assign mdata = md_ena ? md : 8'hZZ;
        //
        //
        always @*
        begin
                if( !memoe_n && !romcs_n ) // ROM directly
                begin
                        seed = $random( {romcs_n, mema19, mema15, mema14, ma13, ma12, ma11, ma10, ma7, ma6} );
                        seed = $random;
                        last_mem_data = $random>>24;
                        romd = last_mem_data;
                        romd_ena = 1'b1;
                end
                else
                        romd_ena = 1'b0;
        end


        // ROM paging and data tracer
        always @(posedge clkin)
        if( !romcs_n && !mreq_n && !old_mreq_n && ( (!memwe_n && !old_memwe_n) || (!memoe_n && !old_memoe_n) ) )
        begin
                if( memwe_n )
                begin // read ROM
                        memop_type = READ;
                        memop_page = {mema15,mema14};
                        memop_data = zdata;
                end
                else
                begin // write ROM
                        memop_type = WRITE;
                        memop_page = {mema15,mema14};
                        memop_data = zdata;
                end
        end

        // RAM paging and data tracer
        always @(posedge clkin)
        if( !out_ramcs0_n && !mreq_n && !old_mreq_n && ( (!memwe_n && !old_memwe_n) || (!memoe_n && !old_memoe_n) ) )
        begin
                if( memwe_n )
                begin // read RAM
                        memop_type = READ;
                        memop_page = {mema15,mema14};
                        memop_data = zdata;
                end
                else
                begin // write RAM
                        memop_type = WRITE;
                        memop_page = {mema15,mema14};
                        memop_data = zdata;
                end
        end

        // mema19 and out_ramcs1_n toggle tracers
        initial
        begin
                clr_mema19_ramcs1_toggle = 1'b0;

                #(0.1);

                mema19_toggled = 1'b0;
                ramcs1_toggled = 1'b0;
        end
        //
        always @(clr_mema19_ramcs1_toggle) // clr on request
        begin
                mema19_toggled = 1'b0;
                ramcs1_toggled = 1'b0;
        end
        //
        always @(mema19)
        if( mema19 !== 1'b0 )
                mema19_toggled = 1'b1;
        //
        always @(out_ramcs1_n)
        if( out_ramcs1_n !== 1'b1 )
                ramcs1_toggled = 1'b1;

        // external drive on romcs memoe memwe
        assign romcs_n = edrv ? eromcs_n : 1'bZ;
        assign memoe_n = edrv ? ememoe_n : 1'bZ;
        assign memwe_n = edrv ? ememwe_n : 1'bZ;




















        // tasks for z80 bus model (simplified)

        task memrd;

                input  [15:0] addr;
                output [ 7:0] data;

                begin
                        @(posedge clkin);
                        mreq_n <= 1'b1;
                        iorq_n <= 1'b1;
                        rd_n   <= 1'b1;
                        wr_n   <= 1'b1;
                        zdena  <= 1'b0;
                        zaddr <= addr;

                        @(negedge clkin);

                        mreq_n <= 1'b0;
                        rd_n   <= 1'b0;

                        @(negedge clkin);
                        @(negedge clkin);

                        data = zdata;
                        mreq_n <= 1'b1;
                        rd_n   <= 1'b1;
                end
        endtask


        task memwr;

                input  [15:0] addr;
                input  [ 7:0] data;

                begin
                        @(posedge clkin);

                        mreq_n <= 1'b1;
                        iorq_n <= 1'b1;
                        rd_n   <= 1'b1;
                        wr_n   <= 1'b1;
                        zdena  <= 1'b1;
                        zaddr  <= addr;
                        zdout  <= data;

                        @(negedge clkin);

                        mreq_n <= 1'b0;
                        wr_n   <= 1'b0;

                        @(negedge clkin);
                        @(negedge clkin);

                        mreq_n <= 1'b1;
                        wr_n   <= 1'b1;
                        wait(wr_n==1'b1); // delta-cycle delay!!!
                        zdena  <= 1'b0;
                end
        endtask


        task iord;

                input [15:0] addr;

                output [7:0] data;

                begin

                        @(posedge clkin);

                        mreq_n <= 1'b1;
                        iorq_n <= 1'b1;
                        rd_n   <= 1'b1;
                        wr_n   <= 1'b1;

                        zdena  <= 1'b0;

                        zaddr <= addr;

                        @(negedge clkin);

                        iorq_n <= 1'b0;
                        rd_n   <= 1'b0;

                        @(negedge clkin);
                        @(negedge clkin);

                        data = zdata;

                        iorq_n <= 1'b1;
                        rd_n   <= 1'b1;

                end

        endtask


        task iowr;

                input [15:0] addr;
                input [ 7:0] data;

                begin

                        @(posedge clkin);

                        mreq_n <= 1'b1;
                        iorq_n <= 1'b1;
                        rd_n   <= 1'b1;
                        wr_n   <= 1'b1;

                        zdena  <= 1'b1;

                        zaddr <= addr;
                        zdout <= data;

                        @(negedge clkin);

                        iorq_n <= 1'b0;
                        wr_n   <= 1'b0;

                        @(negedge clkin);
                        @(negedge clkin);

                        iorq_n <= 1'b1;
                        wr_n   <= 1'b1;

                        wait(wr_n==1'b1); // delta-cycle delay!!!

                        zdena  <= 1'b0;

                end

        endtask


        task w_st_n; // wait status_n to be as given

                input value;

                reg [7:0] tmp;

                forever
                begin

                iord(16'h0080,tmp);

                        //$display("status_n=d",tmp[7]);

                        if( tmp[7]==value )
                                disable w_st_n;

                end

        endtask



        task test_config_status;

                begin
                        $display("test_config_status: playing with config_n...");

                        w_st_n(1'b0);
                        iowr(16'h0080,8'h01); // play with config_n
                        w_st_n(1'b1);
                        iowr(16'h0080,8'h00);
                        w_st_n(1'b0);
                        iowr(16'h0080,8'h01);
                        w_st_n(1'b1);

                        $display("test_config_status: success!");
                end

        endtask


        task test_cold_reset_flag;

                input cold_reset_set;


                reg [7:0] tmp;

                begin
                        $display("test_cold_reset_flag: doing sticking test...");

                        iord(16'h0040,tmp);
                        if( tmp[7] && cold_reset_set )
                        begin
                                $display("test_cold_reset_flag: error! cold_reset_flag was set at the beginning!");
                                $stop;
                        end

                        iowr(16'h0080,8'h81); // set cold reset flag

                        iord(16'h0040,tmp);
                        if( !tmp[7] )
                        begin
                                $display("test_cold_reset_flag: error! can't set cold_reset_flag!");
                                $stop;
                        end

                        iowr(16'h0080,8'h01); // try to clear cold reset flag

                        iord(16'h0040,tmp);
                        if( !tmp[7] )
                        begin
                                $display("test_cold_reset_flag: error! can clear cold_reset_flag!");
                                $stop;
                        end

                        $display("test_cold_reset_flag: success!");
                end

        endtask


        task test_fpga_cs;

                integer i;

                begin
                        $display("test_fpga_cs: testing cs decoding...");

                        for(i=0;i<4;i=i+1)
                        begin

                                @(posedge clkin);
                                zaddr <= { 8'd0, i[1:0], 6'd0 };
                                @(posedge clkin);

                                if( cs!=(i==3) )
                                begin
                                        $display("test_fpga_cs: error! cs is not set at addr $C0!");
                                        $stop;
                                end
                        end

                        $display("test_fpga_cs: success!");
                end

        endtask


        task test_conf_done;

                integer i;

                reg [7:0] tmp;

                begin
                        $display("test_conf_done: testing read of conf_done...");

                        for(i=0;i<2;i=i+1)
                        begin
                                @(posedge clkin);
                                conf_done <= i[0];
                                @(posedge clkin);

                                iord(16'h0080,tmp);

                                if( tmp[0]!=i[0] )
                                begin
                                        $display("test_conf_done: error! read data is wrong!");
                                        $stop;
                                end
                        end

                        $display("test_conf_done: success!");
                end

        endtask




        task test_rommap; // test rom paging

                integer i;

                reg [7:0] tmp;

                begin
                        $display("test_rommap: testing CPLD mapping of ROM...");

                        memwr(16'h0f23,8'h55);
                        if( memop_type!=WRITE || memop_page!=2'b00 || memop_data!=8'h55 )
                        begin
                                $display("test_rommap: error! write to cpu bank 0 fails!");
                                $stop;
                        end

                        memrd(16'h3210,tmp);
                        if( memop_type!=READ || memop_page!=2'b00 || tmp!=last_mem_data )
                        begin
                                $display("test_rommap: error! read from cpu bank 0 fails!");
                                $stop;
                        end

                        for(i=0;i<4;i=i+1)
                        begin
                                iowr(16'h0040,{ 7'd0, i[1] } ); // low or high part of 64k rom slice

                                memwr( { 1'b1, i[0], 14'h29ac }, 8'hAA );
                                if( memop_type!=WRITE || memop_page!=i[1:0] || memop_data!=8'hAA )
                                begin
                                        $display("test_rommap: error! write to cpu banks 2 or 3 fails!");
                                        $stop;
                                end

                                memrd( { 1'b1, i[0], 14'h25ac }, tmp );
                                if( memop_type!=READ || memop_page!=i[1:0] || tmp!=last_mem_data )
                                begin
                                        $display("test_rommap: error! read from cpu banks 2 or 3 fails!");
                                        $stop;
                                end
                        end

                        $display("test_rommap: success!");
                end

        endtask


        task test_rammap;

                integer i;

                reg [7:0] tmp;

                begin
                        $display("test_rammap: testing CPLD mapping of RAM...");

                        memwr(16'h7fff,8'h33);
                        if( memop_type!=WRITE || memop_page!=2'b00 || memop_data!=8'h33 )
                        begin
                                $display("test_rammap: error! write to cpu bank 1 fails!");
                                $stop;
                        end

                        memrd(16'h4000,tmp);
                        if( memop_type!=READ || memop_page!=2'b00 || tmp!=last_mem_data )
                        begin
                                $display("test_rammap: error! read from cpu bank 1 fails!");
                                $stop;
                        end


                        for(i=0;i<4;i=i+1)
                        begin
                                iowr(16'h0040,{ 1'b1, 6'd0, i[0] } ); // low or high part of 64k ram slice

                                memwr( { 1'b1, i[1], 14'h1555 }, 8'hCC );
                                if( memop_type!=WRITE || memop_page!={i[0],i[1]} || memop_data!=8'hCC )
                                begin
                                        $display("test_rammap: error! write to cpu banks 2 or 3 fails!");
                                        $stop;
                                end

                                memrd( { 1'b1, i[1], 14'h2AAA }, tmp );
                                if( memop_type!=READ || memop_page!={i[0],i[1]} || tmp!=last_mem_data )
                                begin
                                        $display("test_rammap: error! read from cpu banks 2 or 3 fails!");
                                        $stop;
                                end
                        end




                        $display("test_rammap: success!");
                end

        endtask




        task test_cpldoff; // test turning off CPLD and then - mapping of FPGA accesses

                begin
                        $display("test_cpldoff: testing CPLD going offline...");

                        // check some signals are correct prior to turning CPLD off
                        if( mema19_toggled || ramcs1_toggled )
                        begin
                                $display("test_cpldoff: error! mema19 or out_ramcs1_n were toggling prior to CPLD turn-off!");
                                $stop;
                        end

                        @(posedge clkin);

                        init_done <= 1'b1; // here CPLD must shut off

                        repeat(4) @(posedge clkin);

                        if( mema14  !== 1'bZ ||
                            mema15  !== 1'bZ ||
                            romcs_n !== 1'bZ ||
                            memoe_n !== 1'bZ ||
                            memwe_n !== 1'bZ ||
                            cs      !== 1'bZ )
                        begin
                                $display("test_cpldoff: error! CPLD did not shut up outputs (mema14 etc.)!");
                                $stop;
                        end

                        if( warmres_n !== 1'b0 )
                        begin
                                $display("test_cpldoff: error! CPLD did not assert warmres_n after disabling!");
                                $stop;
                        end

                        wait( warmres_n!==1'b0 );
                        @(posedge clkin);

                        edrv = 1'b1;

                        @(posedge clkin);
                        @(posedge clkin);

                        $display("test_cpldoff: success!");
                end

        endtask





        task test_ramcs_fpga;

                integer i;

                begin
                        $display("test_ramcs_fpga: testing muxing 4 ramcses into 2 with extra address...");

                        for(i=0;i<4;i=i+1)
                        begin
                                @(posedge clkin);
                                { in_ramcs3_n, in_ramcs2_n, in_ramcs1_n, in_ramcs0_n } <= ~(4'b0001<<i);
                                @(posedge clkin);

                                if( mema19 != i[0]          ||
                                    out_ramcs0_n != i[1]    ||
                                    out_ramcs1_n != (~i[1]) )
                                begin
                                        $display("test_ramcs_fpga: error!");
                                        $stop;
                                end
                        end

                        @(posedge clkin);
                        in_ramcs3_n <= 1'b1;

                        $display("test_ramcs_fpga: success!");
                end

        endtask



        task test_fwd_fpga;


                begin
                        $display("test_fwd_fpga: testing forwarding of ram data during fpga active...");


                        @(posedge clkin);

                        eromcs_n <= 1'b1;
                        ememoe_n <= 1'b0;
                        in_ramcs0_n <= 1'b0;

                        @(posedge clkin);

                        if( zdata!==last_mem_data )
                        begin
                                $display("test_fwd_fpga: error! no data forwarding from RAM side!");
                                $stop;
                        end

                        ememoe_n <= 1'b1;

                        @(posedge clkin);

                        ememwe_n <= 1'b0;
                        zdena <= 1'b1;
                        zdout <= $random>>24;

                        @(posedge clkin);

                        if( mdata!==zdout )
                        begin
                                $display("test_fwd_fpga: error! no data forwarding from Z80 side!");
                                $stop;
                        end

                        zdena <= 1'b0;
                        ememwe_n <= 1'b1;
                        in_ramcs0_n <= 1'b1;


                        $display("test_fwd_fpga: success!");
                end
        endtask




        task test_restart;

                begin
                        $display("test_restart: restarting CPLD...");


                        iowr(16'h0080,8'h00);

                        edrv <= 1'b0;



                        $display("test_restart: success!");
                end
        endtask



endmodule