Top secrets sources NedoPC pentevo

Rev

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

// simulate fpga top-level with external dram, rom, z80
// (c) 2010-2016 NedoPC

`include "../include/tune.v"



//`define ZLOG 1



`define HALF_CLK_PERIOD (17.8)

`define ZCLK_DELAY      (9.5)

// toshibo
//`define Z80_DELAY_DOWN  (17.0)
//`define Z80_DELAY_UP    (22.0)

// z0840008
`define Z80_DELAY_DOWN   34
`define Z80_DELAY_UP     30

module tb;

        reg fclk;

        wire clkz_out,clkz_in;

        reg iorq_n,mreq_n,rd_n,wr_n; // has some delays relative to z*_n (below)
        reg m1_n,rfsh_n;             //

        wire res;                    //
        tri1 ziorq_n,zmreq_n,zrd_n,zwr_n,zm1_n,zrfsh_n; // connected to Z80

        tri1 int_n,wait_n,nmi_n;
        wire zint_n,zwait_n,znmi_n;

        wire [15:0] #((`Z80_DELAY_DOWN+`Z80_DELAY_UP)/2) za;
        wire [ 7:0] #((`Z80_DELAY_DOWN+`Z80_DELAY_UP)/2) zd;
//      wire [15:0] za;
//      wire [ 7:0] zd;

        tri1 [ 7:0] zd_dut_to_z80;
//      wire [ 7:0] zd_z80_to_dut;


        reg [15:0] reset_pc = 16'h0000;
        reg [15:0] reset_sp = 16'hFFFF;



        wire csrom, romoe_n, romwe_n;
        wire rompg0_n, dos_n;
        wire rompg2,rompg3,rompg4;

        wire [15:0] rd;
        wire [9:0] ra;
        wire rwe_n,rucas_n,rlcas_n,rras0_n,rras1_n;


        tri0 [15:0] ide_d;


        wire hsync,vsync;
        wire [1:0] red,grn,blu;



        // sdcard
        wire sdcs_n, sddo, sddi, sdclk;

        // avr
        wire spick, spidi, spido, spics_n;




        assign zwait_n = (wait_n==1'b0) ? 1'b0 : 1'b1;
        assign znmi_n = (nmi_n==1'b0) ? 1'b0 : 1'b1;
        assign zint_n = (int_n==1'b0) ? 1'b0 : 1'b1;






        initial
        begin

                fclk = 1'b0;

                forever #`HALF_CLK_PERIOD fclk = ~fclk;
        end


        assign #`ZCLK_DELAY clkz_in = ~clkz_out;







        top DUT( .fclk(fclk),
                 .clkz_out(clkz_out),
                 .clkz_in(clkz_in),

               // z80
                 .iorq_n(iorq_n),
                 .mreq_n(mreq_n),
                 .rd_n(rd_n),
                 .wr_n(wr_n),
                 .m1_n(m1_n),
                 .rfsh_n(rfsh_n),
                 .int_n(int_n),
                 .nmi_n(nmi_n),
                 .wait_n(wait_n),
                 .res(res),
                 //
                 .d(zd),
                 .a(za),

                 // ROM
                 .csrom(csrom),
                 .romoe_n(romoe_n),
                 .romwe_n(romwe_n),
                 .rompg0_n(rompg0_n),
                 .dos_n(dos_n),
                 .rompg2(rompg2),
                 .rompg3(rompg3),
                 .rompg4(rompg4),

                 // DRAM
                 .rd(rd),
                 .ra(ra),
                 .rwe_n(rwe_n),
                 .rucas_n(rucas_n),
                 .rlcas_n(rlcas_n),
                 .rras0_n(rras0_n),
                 .rras1_n(rras1_n),

                 // ZX-bus
                 .iorqge1(1'b0),
                 .iorqge2(1'b0),

                 // IDE
                 .ide_d(ide_d),
                 .ide_rdy(1'b1),

                 // VG93
                 .step(1'b0),
                 .vg_sl(1'b0),
                 .vg_sr(1'b0),
                 .vg_tr43(1'b0),
                 .rdat_b_n(1'b1),
                 .vg_wf_de(1'b0),
                 .vg_drq(1'b1),
                 .vg_irq(1'b1),
                 .vg_wd(1'b0),

                 // SDcard SPI
                 .sddi(sddi),
                 .sddo(sddo),
                 .sdcs_n(sdcs_n),
                 .sdclk(sdclk),

                 // ATmega SPI
                 .spics_n(spics_n),
                 .spick(spick),
                 .spido(spido),
                 .spidi(spidi),

                 .vhsync(hsync),
                 .vvsync(vsync),
                 .vred(red),
                 .vgrn(grn),
                 .vblu(blu)

               );




//      assign zd_dut_to_z80 = tb.DUT.ena_ram ? tb.DUT.dout_ram : ( tb.DUT.ena_ports ? tb.DUT.dout_ports : ( tb.DUT.drive_ff ? 8'hFF : 8'bZZZZZZZZ ) );
        assign zd_dut_to_z80 = tb.DUT.d_ena ? tb.DUT.d_pre_out : 8'bZZZZ_ZZZZ;




        wire zrst_n = ~res;

        T80a z80( .RESET_n(zrst_n),
                  .CLK_n(clkz_in),
                  .WAIT_n(zwait_n),
                  .INT_n(zint_n),
                  .NMI_n(znmi_n),
                  .M1_n(zm1_n),
                  .RFSH_n(zrfsh_n),
                  .MREQ_n(zmreq_n),
                  .IORQ_n(ziorq_n),
                  .RD_n(zrd_n),
                  .WR_n(zwr_n),
                  .BUSRQ_n(1'b1),
                  .A(za),
//                .D(zd),
                  .D_I(zd_dut_to_z80),
                  .D_O(zd),
                  .ResetPC(reset_pc),
                  .ResetSP(reset_sp)
                );

        // now make delayed versions of signals
        //
        reg  mreq_wr_n;
        wire iorq_wr_n, full_wr_n;
        //
        // first, assure there is no X's at the start
        //
        initial
        begin
                m1_n      = 1'b1;
                rfsh_n    = 1'b1;
                mreq_n    = 1'b1;
                iorq_n    = 1'b1;
                rd_n      = 1'b1;
                wr_n      = 1'b1;
                mreq_wr_n = 1'b1;
        end
        //
        always @(zm1_n)
                if( zm1_n )
                        m1_n <= #`Z80_DELAY_UP zm1_n;
                else
                        m1_n <= #`Z80_DELAY_DOWN zm1_n;
        //
        always @(zrfsh_n)
                if( zrfsh_n )
                        rfsh_n <= #`Z80_DELAY_UP zrfsh_n;
                else
                        rfsh_n <= #`Z80_DELAY_DOWN zrfsh_n;
        //
        always @(zmreq_n)
                if( zmreq_n )
                        mreq_n <= #`Z80_DELAY_UP zmreq_n;
                else
                        mreq_n <= #`Z80_DELAY_DOWN zmreq_n;
        //
        always @(ziorq_n)
                if( ziorq_n )
                        iorq_n <= #`Z80_DELAY_UP ziorq_n;
                else
                        iorq_n <= #`Z80_DELAY_DOWN ziorq_n;
        //
        always @(zrd_n)
                if( zrd_n )
                        rd_n <= #`Z80_DELAY_UP zrd_n;
                else
                        rd_n <= #`Z80_DELAY_DOWN zrd_n;
        //
        //
        // special handling for broken T80 WR_n
        //
        always @(negedge clkz_in)
                mreq_wr_n <= zwr_n;
        //
        assign iorq_wr_n = ziorq_n | (~zrd_n) | (~zm1_n);
        //
        assign full_wr_n = mreq_wr_n & iorq_wr_n;
        //
        // this way glitches won't affect state of wr_n
        always @(full_wr_n)
                if( !full_wr_n )
                        #`Z80_DELAY_DOWN wr_n <= full_wr_n;
                else
                        #`Z80_DELAY_UP wr_n <= full_wr_n;





        // ROM model
        rom romko(
                   .addr( {rompg4,rompg3,rompg2,dos_n, (~rompg0_n), za[13:0]} ),
                   .data(zd_dut_to_z80),
                   .ce_n( romoe_n | (~csrom) )
                 );

        // DRAM model
        drammem dramko1(
                         .ma(ra),
                         .d(rd),
                         .ras_n(rras0_n),
                         .ucas_n(rucas_n),
                         .lcas_n(rlcas_n),
                         .we_n(rwe_n)
                       );
        //
        drammem dramko2(
                         .ma(ra),
                         .d(rd),
                         .ras_n(rras1_n),
                         .ucas_n(rucas_n),
                         .lcas_n(rlcas_n),
                         .we_n(rwe_n)
                       );
        defparam dramko1._verbose_ = 0;
        defparam dramko2._verbose_ = 0;

        defparam dramko1._init_ = 0;
        defparam dramko2._init_ = 0;



`ifndef GATE

        // trace rom page
        wire rma14,rma15;

        assign rma14 = DUT.page[0][0];
        assign rma15 = DUT.page[0][1];


        always @(rma14 or rma15)
        begin
//              $display("at time %t us",$time/1000000);

//              case( {rma15, rma14} )

//              2'b00: $display("BASIC 48");
//              2'b01: $display("TR-DOS");
//              2'b10: $display("BASIC 128");
//              2'b11: $display("GLUKROM");
//              default: $display("unknown");

//              endcase

//              $display("");
        end


        // trace ram page
        wire [5:0] rpag;

        assign rpag=DUT.page[3][5:0];

        always @(rpag)
        begin
//              $display("at time %t us",$time/1000000);

//              $display("RAM page is %d",rpag);

//              $display("");
        end



        // key presses/nmi/whatsoever
        initial
        begin
                #1;
                tb.DUT.zkbdmus.kbd = 40'd0;
                tb.DUT.zkbdmus.kbd[36] = 1'b1;
                @(negedge int_n);
                @(negedge int_n);
                tb.DUT.zkbdmus.kbd[36] = 1'b0;
        end
/*
        initial
        begin : gen_nmi

                reg [21:0] a;

                #1000000000;

                a = 22'h3FC066;

                put_byte(a,8'hF5); a=a+1;
                put_byte(a,8'hC5); a=a+1;
                put_byte(a,8'hD5); a=a+1;
                put_byte(a,8'hE5); a=a+1;

                put_byte(a,8'h10); a=a+1;
                put_byte(a,8'hFE); a=a+1;

                put_byte(a,8'h14); a=a+1;

                put_byte(a,8'h01); a=a+1;
                put_byte(a,8'hFE); a=a+1;
                put_byte(a,8'h7F); a=a+1;

                put_byte(a,8'hED); a=a+1;
                put_byte(a,8'h51); a=a+1;

                put_byte(a,8'hED); a=a+1;
                put_byte(a,8'h78); a=a+1;

                put_byte(a,8'h1F); a=a+1;

                put_byte(a,8'hDA); a=a+1;
                put_byte(a,8'h6A); a=a+1;
                put_byte(a,8'h00); a=a+1;

                put_byte(a,8'hE1); a=a+1;
                put_byte(a,8'hD1); a=a+1;
                put_byte(a,8'hC1); a=a+1;
                put_byte(a,8'hF1); a=a+1;

                put_byte(a,8'hD3); a=a+1;
                put_byte(a,8'hBE); a=a+1;

                put_byte(a,8'hED); a=a+1;
                put_byte(a,8'h45); a=a+1;


                @(posedge fclk);
                tb.DUT.slavespi.cfg0_reg_out[1] = 1'b1;
                @(posedge fclk);
                tb.DUT.slavespi.cfg0_reg_out[1] = 1'b0;

                #64000000;

                tb.DUT.zkbdmus.kbd[39] = 1'b1;
                @(negedge int_n);
                tb.DUT.zkbdmus.kbd[39] = 1'b0;
        end
*/


`endif








`ifdef ZLOG
        reg [ 7:0] old_opcode;
        reg [15:0] old_opcode_addr;

        wire [7:0] zdd = zd_dut_to_z80;

        reg was_m1;

        always @(zm1_n)
        if( zm1_n )
                was_m1 <= 1'b0;
        else
                was_m1 = 1'b1;

        always @(posedge (zmreq_n | zrd_n | zm1_n | (~zrfsh_n)) )
        if( was_m1 )
        begin
                if( (zdd!==old_opcode) || (za!==old_opcode_addr) )
                begin
                        if( tb.DUT.z80mem.romnram )
//                              $display("Z80OPROM: addr %x, opcode %x, time %t",za,zdd,$time);
                                $display("Z80OPROM: addr %x, opcode %x",za,zdd);
                        else
//                              $display("Z80OPRAM: addr %x, opcode %x, time %t",za,zdd,$time);
                                $display("Z80OPRAM: addr %x, opcode %x",za,zdd);
                end

                old_opcode      = zdd;
                old_opcode_addr = za;
        end

        always @(posedge (zmreq_n | zrd_n | (~zm1_n) | (~zrfsh_n)) )
        if( !was_m1 )
        begin
                if( tb.DUT.z80mem.romnram )
//                      $display("Z80RDROM: addr %x, rddata %x, time %t",za,zdd,$time);
                        $display("Z80RDROM: addr %x, rddata %x",za,zdd);
                else
//                      $display("Z80RDRAM: addr %x, rddata %x, time %t",za,zdd,$time);
                        $display("Z80RDRAM: addr %x, rddata %x",za,zdd);
        end

        always @(posedge (zmreq_n | zwr_n | (~zm1_n) | (~zrfsh_n)) )
        begin
                if( tb.DUT.z80mem.romnram )
//                      $display("Z80WRROM: addr %x, wrdata %x, time %t",za,zd,$time);
                        $display("Z80WRROM: addr %x, wrdata %x",za,zd);
                else
//                      $display("Z80WRRAM: addr %x, wrdata %x, time %t",za,zd,$time);
                        $display("Z80WRRAM: addr %x, wrdata %x",za,zd);
        end
`endif




        // turbo
`ifdef C7MHZ
        initial
                force tb.DUT.zclock.turbo = 2'b01;
`else
        `ifdef C35MHZ

                initial
                        force tb.DUT.zclock.turbo = 2'b00;

        `endif
`endif


        // raster type
`ifdef CCONTEND
        initial
                force tb.DUT.modes_raster = 2'b10;
`endif




`ifdef NMITEST2
 `define M48K

        initial
        begin
                int i,fd;
                logic [7:0] ldbyte;

                reset_pc=16'h8000;
                reset_sp=16'h8000;

                fd = $fopen("dimkanmi.bin","rb");
                if( !fd )
                begin
                        $display("Can't open 'dimkanmi.bin'!");
                        $stop;
                end

                i='h8000;

                begin : load_loop
                        while(1)
                        begin
                                if( 1!=$fread(ldbyte,fd) ) disable load_loop;
                                put_byte_48k(i,ldbyte);
                                i=i+1;
                        end
                end
                $fclose(fd);


                wait(res===1'b0);
                #(0.2);
                tb.DUT.zports.atm_turbo = 1'b1;
                tb.DUT.zports.peff7_int[4] = 1'b0;
               
               
                #(100000); // 100 us

                //force nmi_n = 1'b0;
                @(posedge fclk);
                force tb.DUT.imm_nmi = 1'b1;
                @(posedge fclk);
                release tb.DUT.imm_nmi;
        end
`endif



`ifdef NMITEST3
 `define M48K

        initial
        begin
                int i,fd;
                logic [7:0] ldbyte;

                reset_pc=16'h0068;
                reset_sp=16'h8000;


                #(0.1); // let M48K rom load execute

                fd = $fopen("dimkarom.bin","rb");
                if( !fd )
                begin
                        $display("Can't open 'dimkarom.bin'!");
                        $stop;
                end

                i='h0066;
                begin : load_loop
                        while(1)
                        begin
                                if( 1!=$fread(ldbyte,fd) ) disable load_loop;
                                tb.romko.zxevo_rom.mem[i]=ldbyte;
                                i=i+1;
                        end
                end
                $fclose(fd);


                wait(res===1'b0);
                #(0.2);
                tb.DUT.zports.atm_turbo = 1'b1;
                tb.DUT.zports.peff7_int[4] = 1'b0;
               
               
                #(1000000); // 1 ms

                //force nmi_n = 1'b0;
                @(posedge fclk);
                force tb.DUT.imm_nmi = 1'b1;
                @(posedge fclk);
                release tb.DUT.imm_nmi;
        end
`endif


        // port #FE monitor
        wire fe_write;
        assign fe_write = (za[7:0]==8'hFE) && !wr_n && !iorq_n;
        always @(negedge fe_write)
                $display("port #FE monitor: border is %d at %t",zd[2:0],$time());
        always @(negedge nmi_n)
                $display("nmi monitor: negative edge at %t",$time());  




        // start in 48k mode
`ifdef M48K
        initial
        begin : force_48k_mode

                int i;
                int fd;
       
                fd = $fopen("48.rom","rb");
                if( 16384!=$fread(tb.romko.zxevo_rom.mem,fd) )
                begin
                        $display("Couldn't load 48k ROM!\n");
                        $stop;
                end
                $fclose(fd);
               
               
                wait(res===1'b0);
                #(0.1);

                tb.DUT.zports.atm_turbo = 1'b0;
                tb.DUT.zports.atm_pen = 1'b0;
                tb.DUT.zports.atm_cpm_n = 1'b1;
                tb.DUT.zports.atm_pen2 = 1'b0;
//              tb.DUT.zports.pent1m_ram0_0 = 1'b0;
//              tb.DUT.zports.pent1m_1m_on = 1'b0;
//              tb.DUT.zports.pent1m_page = 'd0;
//              tb.DUT.zports.pent1m_ROM = 1'b1;

                tb.DUT.zdos.dos = 1'b0;

/*              tb.DUT.page[0] = 'd0;
                tb.DUT.page[1] = 'd5;
                tb.DUT.page[2] = 'd2;
                tb.DUT.page[3] = 'd0;
                tb.DUT.romnram[0] = 1'b1;
                tb.DUT.romnram[1] = 1'b0;
                tb.DUT.romnram[2] = 1'b0;
                tb.DUT.romnram[3] = 1'b0;*/


                tb.DUT.instantiate_atm_pagers[0].atm_pager.pages[0] = 'd0;
                tb.DUT.instantiate_atm_pagers[1].atm_pager.pages[0] = 'd5;
                tb.DUT.instantiate_atm_pagers[2].atm_pager.pages[0] = 'd2;
                tb.DUT.instantiate_atm_pagers[3].atm_pager.pages[0] = 'd0;
                tb.DUT.instantiate_atm_pagers[0].atm_pager.pages[1] = 'd0;
                tb.DUT.instantiate_atm_pagers[1].atm_pager.pages[1] = 'd5;
                tb.DUT.instantiate_atm_pagers[2].atm_pager.pages[1] = 'd2;
                tb.DUT.instantiate_atm_pagers[3].atm_pager.pages[1] = 'd0;

                tb.DUT.instantiate_atm_pagers[0].atm_pager.ramnrom[0] = 'd0;
                tb.DUT.instantiate_atm_pagers[1].atm_pager.ramnrom[0] = 'd1;
                tb.DUT.instantiate_atm_pagers[2].atm_pager.ramnrom[0] = 'd1;
                tb.DUT.instantiate_atm_pagers[3].atm_pager.ramnrom[0] = 'd1;
                tb.DUT.instantiate_atm_pagers[0].atm_pager.ramnrom[1] = 'd0;
                tb.DUT.instantiate_atm_pagers[1].atm_pager.ramnrom[1] = 'd1;
                tb.DUT.instantiate_atm_pagers[2].atm_pager.ramnrom[1] = 'd1;
                tb.DUT.instantiate_atm_pagers[3].atm_pager.ramnrom[1] = 'd1;

                tb.DUT.zports.atm_scr_mode = 3'b011;
               
/*              tb.DUT.peff7[5] = 1'b0;
                tb.DUT.peff7[0] = 1'b0;
                tb.DUT.p7ffd[3] = 1'b0;*/

//              tb.DUT.zports.peff7[7] = 1'b0;
//              tb.DUT.zports.peff7[0] = 1'b0;
//              tb.DUT.zports.p7ffd[3] = 1'b0;

                tb.DUT.zports.peff7_int = 8'h14;
                tb.DUT.zports.p7ffd_int = 8'h30;



                for(i=0;i<512;i=i+1)
                begin : set_palette //                                            R                               G                              B
                        tb.DUT.video_top.video_palframe.palette[i] = { (i[1]?{1'b1,i[3]}:2'b00), 1'b0, (i[2]?{1'b1,i[3]}:2'b00), 1'b0, (i[0]?{1'b1,i[3]}:2'b00) };
                end

        end
`endif


        // load and start some code after we've reached "1982 Sinclair research ltd"
`ifdef START_LOAD
        initial
        begin
                int i,fd;
                logic [7:0] ldbyte;

                wait( za==16'h15e0 && zmreq_n==1'b0 && zrd_n == 1'b0 );
               
                $display("loading and starting...");

                fd = $fopen(`START_NAME,"rb");
                for(i=`START_ADDR;i<`START_ADDR+`START_LEN;i=i+1)
                begin
                        if( 1!=$fread(ldbyte,fd) )
                        begin
                                $display("can't read byte from input file!");
                                $stop;
                        end

                        put_byte_48k(i,ldbyte);
                end
                $fclose(fd);

                $display("load ok!");

                reset_pc = 16'h9718;
                reset_sp = 16'h6000;
                @(posedge clkz_in);
                force tb.zrst_n = 1'b0;
                repeat(3) @(posedge clkz_in);
                release tb.zrst_n;
                @(posedge clkz_in);
                reset_pc = 16'h0000;
                reset_sp = 16'hFFFF;
        end
`endif










        // force fetch mode
//      initial
//      begin
//              force tb.DUT.dramarb.bw = 2'b11;
//
//              #(64'd2400000000);
//
//              release tb.DUT.dramarb.bw;
//      end



`ifndef NO_PIXER
        // picture out
        pixer pixer
        (
                .clk(fclk),

                .vsync(vsync),
                .hsync(hsync),
                .red(red),
                .grn(grn),
                .blu(blu)
        );
`endif


/*
        // time ticks
        always
        begin : timemark

                integer ms;

                ms = ($time/1000000);

//              $display("timemark %d ms",ms);

                #10000000.0; // 1 ms
        end
*/



        // init dram
`ifndef NMITEST2
        initial
        begin : init_dram
                integer i;

                for(i=0;i<4*1024*1024;i=i+1)
                begin
                        put_byte(i,(i%257));
                end
        end
`endif





        // cmos simulation
        wire [7:0] cmos_addr;
        wire [7:0] cmos_read;
        wire [7:0] cmos_write;
        wire       cmos_rnw;
        wire       cmos_req;

        cmosemu cmosemu
        (
                .zclk(clkz_in),

                .cmos_req  (cmos_req  ),
                .cmos_addr (cmos_addr ),
                .cmos_rnw  (cmos_rnw  ),
                .cmos_read (cmos_read ),
                .cmos_write(cmos_write)
        );

        assign cmos_req   = tb.DUT.wait_start_gluclock;
        assign cmos_rnw   = tb.DUT.wait_rnw;
        assign cmos_addr  = tb.DUT.gluclock_addr;
        assign cmos_write = tb.DUT.wait_write;

        always @*
                force tb.DUT.wait_read = cmos_read;




`ifdef SPITEST
        // spitest printing module
        // does not hurt at any time (yet), so attached forever

        spitest_print spitest_print(
                .sdclk (sdclk ),
                .sddi  (sddi  ),
                .sddo  (sddo  ),
                .sdcs_n(sdcs_n)
        );

        // spitest AVR imitator

        spitest_avr spitest_avr(
                .spick  (spick  ),
                .spics_n(spics_n),
                .spido  (spido  ),
                .spidi  (spidi  )
        );
`else
        assign sddi = 1'b1;

        assign spics_n = 1'b1;
        assign spick   = 1'b0;
        assign spido   = 1'b1;
`endif





//      // set up breakpoint
//      initial
//      begin
//              #(650_000_000); // wait 650ms = 650*1000*1000 ns
//
//              @(posedge fclk);
//
//              tb.DUT.zports.brk_ena  = 1'b1;
//              tb.DUT.zports.brk_addr = 16'h0041;
//      end











        task put_byte;

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



                reg [19:0] arraddr;

                begin

                        arraddr = { addr[21:12], addr[11:2] };

                        case( addr[1:0] ) // chipsel, bytesel

                        2'b00: tb.dramko1.array[arraddr][15:8] = data;
                        2'b01: tb.dramko1.array[arraddr][ 7:0] = data;
                        2'b10: tb.dramko2.array[arraddr][15:8] = data;
                        2'b11: tb.dramko2.array[arraddr][ 7:0] = data;

                        endcase
                end

        endtask

        task put_byte_48k
        (
                input [15:0] addr,
                input [ 7:0] data
        );

                case( addr[15:14] )
                        2'b01: put_byte(addr-16'h4000 + 22'h14000,data);
                        2'b10: put_byte(addr-16'h8000 + 22'h08000,data);
                        2'b11: put_byte(addr-16'hc000 + 22'h00000,data);
                endcase
        endtask




endmodule