Top secrets sources NedoPC tsfmpro

Rev

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

// TurboFMpro project
// (C) 2018 NedoPC

// bus control:
// data buffering, async signals filtering, access cycles forming

// ym2203 info:
//  address setup: 10ns (min 1Tc)
//  cs/rd/wr pulse width: 250ns (min 14Tc)
// total: 15Tc
//  read time: 250ns -- read will only work at Z80@7MHz or slower!
// ymA0=0 -- wr addr/read status
// ymA0=1 -- wr data/read data
//
// saa1099 info:
//  address setup: 0ns
//  wr pulse width: 100ns (min 6Tc)
//  cs to wr min: 50ns (min 3Tc)
// total: 9Tc
// saaA0=0 -- data, saaA0=1 -- address
//
// Z80 @ 14MHz:
//  access width: 178ns
//  min repetition time: 785ns
//
// 56MHz period: 17.8ns
//
//
// time plan:
// fclk:          __/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\__/``\
// async access:  ___/````````

// resync1:       _________/```````
// resync2:       _______________/``````
// filt:          _____________________/`````````````
// output cs/wr:  ___________________________/````````````
//
// deltaT:           |<--------------------->| = 4Tc = 71ns -> less than Z80@14MHz /IORQ length
//






module bus
(
        input  wire clk,
        input  wire rst_n,

        input  wire        aybc1,
        input  wire        aybc2,
        input  wire        aybdir,
        input  wire        aya8,
        input  wire        aya9_n,

        // data busses
        inout  wire [7:0]  ayd, // INPUT DATA BUS!!! (from host)
        inout  wire [7:0]  d,   // internal data bus (to ym2203/sa1099)

        // write strobe for Fx config port
        output wire wr_port,
       
        // strobes/addr for ym2203
        output reg  yma0,
        output reg  ymcs0_n,
        output reg  ymcs1_n,
        output reg  ymrd_n,
        output reg  ymwr_n,

        // strobes/addr for saa1099
        output reg  saaa0,
        output reg  saacs_n,
        output reg  saawr_n,



        // config inputs
        input  wire ym_sel,  // 0 -- YM #0 selected, 1 -- YM #1
        input  wire ym_stat, // 1 -- read YM status reg
        input  wire saa_sel  // 1 -- saa selected, 0 -- YM selected
);

        wire [7:0] decode_wraddr;

        wire async_wrport,
             async_wraddr,
             async_wrdata,
             async_rddata;

        reg  [2:0] wrport;
        reg  [2:0] wraddr;
        reg  [2:0] wrdata;
        reg  [2:0] rddata;

        reg wrport_on,
            wraddr_on,
            wrdata_on,
            rddata_on;

        wire wraddr_beg,
             wrdata_beg,
             rddata_beg;

        wire wrport_beg;


        reg [7:0] write_latch;
        reg [7:0] read_latch;



        reg [3:0] saa_ctr = 4'hF; // for simulation

        reg [3:0] ym_ctr  = 4'hF; // for simulation




        // control signals decoding
        //     YM/AY                         YM2203                    
        //  BDIR  BC2  BC1  A8  _A9      _WR  _RD  A0                  
        //   0     0    0   1    0         inactive                    
        //   0     0    1   1    0        0    1   0   (write address)  
        //   0     1    0   1    0         inactive                    
        //   0     1    1   1    0        1    0   1   (read register)  
        //   1     0    0   1    0        0    1   0   (write address)  
        //   1     0    1   1    0         inactive                    
        //   1     1    0   1    0        0    1   1   (write register)
        //   1     1    1   1    0        0    1   0   (write address)  
        //          other                  inactive                    
        //
        assign decode_wraddr[3'b000] = 1'b0;
        assign decode_wraddr[3'b001] = 1'b1;
        assign decode_wraddr[3'b010] = 1'b0;
        assign decode_wraddr[3'b011] = 1'b0;
        assign decode_wraddr[3'b100] = 1'b1;
        assign decode_wraddr[3'b101] = 1'b0;
        assign decode_wraddr[3'b110] = 1'b0;
        assign decode_wraddr[3'b111] = 1'b1;
        //
        assign async_wrport = decode_wraddr[{aybdir,aybc2,aybc1}] && aya8 && !aya9_n && ayd[7:4]==4'hF;
        assign async_wraddr = decode_wraddr[{aybdir,aybc2,aybc1}] && aya8 && !aya9_n && ayd[7:4]!=4'hF;
        assign async_wrdata =  aybdir &&  aybc2 && !aybc1         && aya8 && !aya9_n;
        assign async_rddata = !aybdir &&  aybc2 &&  aybc1         && aya8 && !aya9_n;



        // resync
        always @(posedge clk)
        begin
                wrport[2:0] <= { wrport[1:0], async_wrport };
                wraddr[2:0] <= { wraddr[1:0], async_wraddr };
                wrdata[2:0] <= { wrdata[1:0], async_wrdata };
                rddata[2:0] <= { rddata[1:0], async_rddata };
        end

        // filtering
        always @(posedge clk, negedge rst_n)
        if( !rst_n )
                wrport_on <= 1'b0;
        else if( !wrport_on && wrport[2:1]==2'b11 )
                wrport_on <= 1'b1;
        else if(  wrport_on && wrport[2:1]==2'b00 )
                wrport_on <= 1'b0;
        //
        always @(posedge clk, negedge rst_n)
        if( !rst_n )
                wraddr_on <= 1'b0;
        else if( !wraddr_on && wraddr[2:1]==2'b11 )
                wraddr_on <= 1'b1;
        else if(  wraddr_on && wraddr[2:1]==2'b00 )
                wraddr_on <= 1'b0;
        //
        always @(posedge clk, negedge rst_n)
        if( !rst_n )
                wrdata_on <= 1'b0;
        else if( !wrdata_on && wrdata[2:1]==2'b11 )
                wrdata_on <= 1'b1;
        else if(  wrdata_on && wrdata[2:1]==2'b00 )
                wrdata_on <= 1'b0;
        //
        always @(posedge clk, negedge rst_n)
        if( !rst_n )
                rddata_on <= 1'b0;
        else if( !rddata_on && rddata[2:1]==2'b11 )
                rddata_on <= 1'b1;
        else if(  rddata_on && rddata[2:1]==2'b00 )
                rddata_on <= 1'b0;

        // start strobes
        assign wrport_beg = !wrport_on && wrport[2:1]==2'b11;
        assign wraddr_beg = !wraddr_on && wraddr[2:1]==2'b11;
        assign wrdata_beg = !wrdata_on && wrdata[2:1]==2'b11;
        assign rddata_beg = !rddata_on && rddata[2:1]==2'b11;




        // saa control
        always @(posedge clk)
        if( saa_sel && (wraddr_beg || wrdata_beg) )
                saa_ctr <= 4'd0;
        else if( !saa_ctr[3] )
                saa_ctr <= saa_ctr + 4'd1;
        //
        always @(posedge clk)
        if( wraddr_beg || wrdata_beg )
                saaa0 <= wraddr_beg;
        //
        always @(posedge clk)
        if( saa_sel && (wraddr_beg || wrdata_beg) )
                saacs_n <= 1'b0;
        else if( saa_ctr[3] )
                saacs_n <= 1'b1;
        //
        always @(posedge clk)
        if( saa_ctr[3] )
                saawr_n <= 1'b1;
        else if( saa_ctr[1] )
                saawr_n <= 1'b0;





        // ym control
        always @(posedge clk)
        if( !saa_sel && (wraddr_beg || wrdata_beg || rddata_beg) )
                ym_ctr[3:0] <= 4'd0;
        else if( !(&ym_ctr[3:1]) /*ym_ctr[3:0]<4'd14*/ )
                ym_ctr[3:0] <= ym_ctr[3:0] + 4'd1;
        //
        always @(posedge clk)
        if( wraddr_beg || wrdata_beg || rddata_beg )
                yma0 <= wrdata_beg || (rddata_beg && !ym_stat);
        //
        always @(posedge clk)
        if( &ym_ctr[3:1] /*ym_ctr[3:0]==4'd14*/ )
        begin
                ymcs0_n <= 1'b1;
                ymcs1_n <= 1'b1;
                ymrd_n  <= 1'b1;
                ymwr_n  <= 1'b1;
        end
        else if( !ym_ctr[3:0] ) // 1 clock after counter start
        begin
                ymcs0_n <=  ym_sel;
                ymcs1_n <= !ym_sel;
                //
                ymrd_n  <= !rddata_on;
                ymwr_n  <= !(wraddr_on || wrdata_on);
        end


        // config port write strobe
        assign wr_port = wrport_beg;





        // write latch
        always @(posedge clk)
        if( wraddr_beg || wrdata_beg )
                write_latch <= ayd;
       
        // read latch
        always @*
        if( !ymrd_n )
                read_latch = d;



        // busses intercommutation
        assign ayd = async_rddata ? read_latch : 8'hZZ;
        //
        assign d = (!saawr_n || !ymwr_n) ? write_latch : 8'hZZ;






endmodule