Top secrets sources NedoPC ngs

Rev

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

// part of NeoGS project (c) 2007-2008 NedoPC
//

// ports $00-$3f are in FPGA, $40-$ff are in CPLD

module ports(

        din,  // NGS z80 cpu DATA BUS inputs
        dout, // NGS z80 cpu DATA BUS outputs
        busin, // direction of bus: =1 - input, =0 - output
        a, // NSG z80 cpu ADDRESS BUS

        iorq_n,mreq_n,rd_n,wr_n, // NGS z80 cpu control signals


        data_port_input, // data_port input from zxbus module (async)
        data_port_output, // data_port output to zxbus module (async to zxbus, sync here)
        command_port_input, // command_port input from zxbus (async)

        data_bit_input, // data_bit from zxbus module (sync)
        command_bit_input, // --//-- (sync)

        data_bit_output, // output to zxbus module
        command_bit_output,

        data_bit_wr, // strobes (positive) to zxbus module, synchronous
        command_bit_wr,


        mode_8chans, // mode outputs for sound_main module
        mode_pan4ch, //

        mode_ramro, // mode outputs for memmap module
        mode_norom,

        mode_pg0, // page registers for memmap module
        mode_pg1,


        clksel0, // clock select (output from FPGA)
        clksel1,


        snd_wrtoggle, // toggle to write sound data to sound system memory
        snd_datnvol,  // whether it's for volume (=0) or for samples (=1)
        snd_addr,     // address: which channel to be written (0-7)
        snd_data,     // actual 8-bit data to be written


        md_din, // mp3 data interface
        md_start,
        md_dreq,
        md_halfspeed,

        mc_ncs, // mp3 control interface
        mc_xrst,
        mc_dout,
        mc_din,
        mc_start,
        mc_speed,
        mc_rdy,

        sd_ncs, // SD card interface
        sd_dout,
        sd_din,
        sd_start,
        sd_det,
        sd_wp,

        led, // LED control
        led_toggle,


        dma_din_modules, // DMA control
        //
        dma_select_zx,
        dma_dout_zx,
        //
        dma_wrstb,
        dma_regsel,


        rst_n,

        cpu_clock // Z80 CPU clock (clk_fpga on schematics)
);


        localparam MPAG      = 6'h00;
        localparam MPAGEX    = 6'h10;

        localparam ZXCMD     = 6'h01;
        localparam ZXDATRD   = 6'h02;
        localparam ZXDATWR   = 6'h03;
        localparam ZXSTAT    = 6'h04;
        localparam CLRCBIT   = 6'h05;

        localparam VOL1      = 6'h06;
        localparam VOL2      = 6'h07;
        localparam VOL3      = 6'h08;
        localparam VOL4      = 6'h09;
        localparam VOL5      = 6'h16;
        localparam VOL6      = 6'h17;
        localparam VOL7      = 6'h18;
        localparam VOL8      = 6'h19;

        localparam DAMNPORT1 = 6'h0a;
        localparam DAMNPORT2 = 6'h0b;

        localparam LEDCTR    = 6'h01;

        localparam GSCFG0    = 6'h0f;

        localparam SCTRL     = 6'h11;
        localparam SSTAT     = 6'h12;

        localparam SD_SEND   = 6'h13;
        localparam SD_READ   = 6'h13;
        localparam SD_RSTR   = 6'h14;

        localparam MD_SEND   = 6'h14; // same as SD_RSTR!!!

        localparam MC_SEND   = 6'h15;
        localparam MC_READ   = 6'h15;

        localparam DMA_MOD   = 6'h1b; // read/write
        localparam DMA_HAD   = 6'h1c; // LSB bits 1:0 are 00 // read/write all
        localparam DMA_MAD   = 6'h1d; //                  01
        localparam DMA_LAD   = 6'h1e; //                  10
        localparam DMA_CST   = 6'h1f; //                  11

        localparam DMA_PORTS = 6'h1c; // mask for _HAD, _MAD, _LAD and _CST ports, two LSBs must be zero

        // FREE PORT ADDRESSES: $0C-$0E, $1A, $20-$3F


        // inputs/outputs description

        input      [7:0] din;
        output reg [7:0] dout;

        output reg busin; // =1 - dbus ins, =0 - dbus outs

        input [15:0] a;

        input iorq_n,mreq_n,rd_n,wr_n;

        input      [7:0] data_port_input;
        input      [7:0] command_port_input;
        output reg [7:0] data_port_output;

        input data_bit_input;
        input command_bit_input;

        output reg data_bit_output;

        output reg command_bit_output;

        output reg data_bit_wr;

        output reg command_bit_wr;

        output reg mode_8chans;

        output reg mode_pan4ch;

        output reg mode_ramro;

        output reg mode_norom;

        output reg [6:0] mode_pg0;
        output reg [6:0] mode_pg1;

        output reg clksel0;
        output reg clksel1;


        output reg snd_wrtoggle;
        output reg snd_datnvol;
        output reg [2:0] snd_addr;
        output reg [7:0] snd_data;


        input rst_n;

        input cpu_clock;




        // SPI interfaces related

        // MP3 data interface
        output [7:0] md_din; // data to MP3 data SPI interface

        output md_start; // start toggle for mp3 data spi

        input md_dreq; // data request from mp3 decoder

        output reg md_halfspeed;


        // MP3 control interface
        output reg mc_ncs; // nCS signal

        output reg mc_xrst; // xRESET signal

        output mc_start; // start toggle

        output reg [1:0] mc_speed;

        input mc_rdy;

        output [7:0] mc_din; // data to send

        input [7:0] mc_dout; // received data


      // SDcard interface
        output reg sd_ncs;

        output sd_start;

        output [7:0] sd_din;

        input [7:0] sd_dout;

        input sd_det;

        input sd_wp;


        // DMA modules control
        //
        output reg [7:0] dma_din_modules;
        //
        input [7:0] dma_dout_zx;
        output reg dma_select_zx;
        //
        output reg dma_wrstb;
        output reg [1:0] dma_regsel;


        // LED control register
        output reg led;
        input led_toggle;



// internal regs & wires

        reg mode_expag; // extended paging mode register

        reg port09_bit5;

        wire port_enabled; // =1 when port address is in enabled region ($00-$3f)
        wire mem_enabled; // =1 when memory mapped sound regs are addressed ($6000-$7FFF)
        reg volports_enabled; // when volume ports are addressed (6-9 and $16-$19)

        reg iowrn_reg; // registered io write signal (all positive edge!)
        reg iordn_reg; // --//--
        reg merdn_reg; // --//--


        reg port_wr; // synchronous positive write pulse (write from z80 to fpga regs)
        reg port_rd;  // synchronous positive read pulse (read done from fpga regs to z80)

        reg memreg_rd; // when memory-mapped sound regs are read






        wire port00_wr;   // specific write and read strobes (1 clock cycle long positive)
        wire p_ledctr_wr;
        wire port02_rd;
        wire port03_wr;
        wire port05_wrrd;
        wire port09_wr;
        wire port0a_wrrd;
        wire port0b_wrrd;
        wire port0f_wr;
        wire port10_wr;

//      wire p_sstat_rd;
//      wire p_sctrl_rd;
        wire p_sctrl_wr;
        wire p_sdsnd_wr;
//      wire p_sdrd_rd;
        wire p_sdrst_rd;
        wire p_mdsnd_wr;
        wire p_mcsnd_wr;
//      wire p_mcrd_rd;

        wire p_dmamod_wr;
        wire p_dmaports_wr;


        reg [2:0] volnum; // volume register number from port address


        reg [2:0] dma_module_select; // which dma module selected: zero - none selected
        localparam DMA_NONE_SELECTED = 3'd0;
        localparam DMA_MODULE_ZX     = 3'd1;
//      localparam DMA_MODULE_...    = 3'd2;

        reg [7:0] dma_dout_modules; // select in data from different modules


// actual code

        //enabled ports
        assign port_enabled = ~(a[7] | a[6]); // $00-$3F

        //enabled mem
        assign mem_enabled = (~a[15]) & a[14] & a[13]; // $6000-$7FFF

        // volume ports enabled
        always @*
        begin
                if( a[5:0]==VOL1 ||
                    a[5:0]==VOL2 ||
                    a[5:0]==VOL3 ||
                    a[5:0]==VOL4 ||
                    a[5:0]==VOL5 ||
                    a[5:0]==VOL6 ||
                    a[5:0]==VOL7 ||
                    a[5:0]==VOL8 )

                        volports_enabled <= 1'b1;
                else
                        volports_enabled <= 1'b0;
        end



        //when data bus outputs
        always @*
        begin
                if( port_enabled && (!iorq_n) && (!rd_n) )
                        busin <= 1'b0; // bus outputs
                else
                        busin <= 1'b1; // bus inputs
        end



        // rd/wr/iorq syncing in and pulses
        always @(posedge cpu_clock)
        begin
                iowrn_reg <= iorq_n | wr_n;
                iordn_reg <= iorq_n | rd_n;

                if( port_enabled && (!iorq_n) && (!wr_n) && iowrn_reg )
                        port_wr <= 1'b1;
                else
                        port_wr <= 1'b0;

                if( port_enabled && (!iorq_n) && (!rd_n) && iordn_reg )
                        port_rd <= 1'b1;
                else
                        port_rd <= 1'b0;

        end

        // mreq syncing and mem read pulse
        always @(negedge cpu_clock)
        begin
                merdn_reg <= mreq_n | rd_n;

                if( mem_enabled && (!mreq_n) && (!rd_n) && merdn_reg )
                        memreg_rd <= 1'b1;
                else
                        memreg_rd <= 1'b0;

        end


        // specific ports strobes
        assign port00_wr   = ( a[5:0]==MPAG      && port_wr            );
        assign port02_rd   = ( a[5:0]==ZXDATRD   && port_rd            );
        assign port03_wr   = ( a[5:0]==ZXDATWR   && port_wr            );
        assign port05_wrrd = ( a[5:0]==CLRCBIT   && (port_wr||port_rd) );
        assign port09_wr   = ( a[5:0]==VOL4      && port_wr            );
        assign port0a_wrrd = ( a[5:0]==DAMNPORT1 && (port_wr||port_rd) );
        assign port0b_wrrd = ( a[5:0]==DAMNPORT2 && (port_wr||port_rd) );
        assign port0f_wr   = ( a[5:0]==GSCFG0    && port_wr            );
        assign port10_wr   = ( a[5:0]==MPAGEX    && port_wr            );


//      assign p_sctrl_rd = ( a[5:0]==SCTRL  && port_rd );
        assign p_sctrl_wr = ( a[5:0]==SCTRL  && port_wr );
//      assign p_sstat_rd = ( a[5:0]==SSTAT  && port_rd );
        assign p_sdsnd_wr = ( a[5:0]==SD_SEND && port_wr );
//      assign p_sdrd_rd  = ( a[5:0]==SD_READ && port_rd );
        assign p_sdrst_rd = ( a[5:0]==SD_RSTR && port_rd );
        assign p_mdsnd_wr = ( a[5:0]==MD_SEND && port_wr );
        assign p_mcsnd_wr = ( a[5:0]==MC_SEND && port_wr );
//      assign p_mcrd_rd  = ( a[5:0]==MC_READ && port_rd );

        assign p_ledctr_wr = ( a[5:0]==LEDCTR && port_wr );

        assign p_dmamod_wr   = ( a[5:0]==DMA_MOD && port_wr );
        assign p_dmaports_wr = ( {a[5:2],2'b00}==DMA_PORTS && port_wr );




        // read from fpga to Z80
        always @*
        begin
                case( a[5:0] )
                ZXCMD: // command register
                        dout <= command_port_input;
                ZXDATRD: // data register
                        dout <= data_port_input;
                ZXSTAT: // status bits
                        dout <= { data_bit_input, 6'bXXXXXX, command_bit_input };
                GSCFG0: // config register #0F
                        dout <= { 1'b0, mode_pan4ch, clksel1, clksel0, mode_expag, mode_8chans, mode_ramro, mode_norom };

                SSTAT:
                        dout <= { 4'd0, mc_rdy, sd_wp, sd_det, md_dreq };
                SCTRL:
                        dout <= { 2'd0, mc_speed[1], md_halfspeed, mc_speed[0], mc_xrst, mc_ncs, sd_ncs };
                SD_READ:
                        dout <= sd_dout;
                SD_RSTR:
                        dout <= sd_dout;
                MC_READ:
                        dout <= mc_dout;


                DMA_MOD:
                        dout <= { 5'd0, dma_module_select };
                DMA_HAD:
                        dout <= dma_dout_modules;
                DMA_MAD:
                        dout <= dma_dout_modules;
                DMA_LAD:
                        dout <= dma_dout_modules;
                DMA_CST:
                        dout <= dma_dout_modules;


                default:
                        dout <= 8'bXXXXXXXX;
                endcase
        end





        // write to $00 and $10 ports ++
        always @(posedge cpu_clock)
        begin
                if( port00_wr==1'b1 ) // port 00
                begin
                        if( mode_expag==1'b0 ) // normal paging
                                mode_pg0[6:0] <= { din[5:0], 1'b0 };
                        else // extended paging
                                mode_pg0[6:0] <= { din[5:0], din[7] };
                end

                if( mode_expag==1'b0 && port00_wr==1'b1 ) // port 10 (when in normal mode, part of port 00)
                        mode_pg1[6:0] <= { din[5:0], 1'b1 };
                else if( mode_expag==1'b1 && port10_wr==1'b1 )
                        mode_pg1[6:0] <= { din[5:0], din[7] };
        end

        // port $03 write ++
        always @(posedge cpu_clock)
        begin
                if( port03_wr==1'b1 )
                        data_port_output <= din;
        end

        // port $09 bit tracing
        always @(posedge cpu_clock)
        begin
                if( port09_wr==1'b1 )
                        port09_bit5 <= din[5];
        end

        // write and reset of port $0F ++
        always @(posedge cpu_clock,negedge rst_n)
        begin
                if( rst_n==1'b0 ) // reset!
                        { mode_pan4ch, clksel1, clksel0, mode_expag, mode_8chans, mode_ramro, mode_norom } <= 7'b0110000;
                else // write to port
                begin
                        if( port0f_wr == 1'b1 )
                        begin
                                { mode_pan4ch, clksel1, clksel0, mode_expag, mode_8chans, mode_ramro, mode_norom } <= din[6:0];
                        end
                end
        end

        // data bit handling
    always @*
    begin
                case( {port02_rd,port03_wr,port0a_wrrd} )
                3'b100:
                begin
                        data_bit_output <= 1'b0;
                        data_bit_wr <= 1'b1;
                end

                3'b010:
                begin
                        data_bit_output <= 1'b1; // ++
                        data_bit_wr <= 1'b1;
                end

                3'b001:
                begin
                        data_bit_output <= ~mode_pg0[0];
                        data_bit_wr <= 1'b1;
                end

                default:
                begin
                        data_bit_output <= 1'bX;
                        data_bit_wr <= 1'b0;
                end
        endcase

    end

        // command bit handling
        always @*
        begin
                casex( {port05_wrrd,port0b_wrrd} )
                2'b10:
                begin
                        command_bit_output <= 1'b0;
                        command_bit_wr <= 1'b1;
                end

                2'b01:
                begin
                        command_bit_output <= port09_bit5;
                        command_bit_wr <= 1'b1;
                end

                default:
                begin
                        command_bit_output <= 1'bX;
                        command_bit_wr <= 1'b0;
                end
                endcase
        end

        // handle data going to sound module (volume and samples values)
        always @*
        begin
                case( a[5:0] ) // port addresses to volume register numbers
                VOL1:
                        volnum <= 3'd0;
                VOL2:
                        volnum <= 3'd1;
                VOL3:
                        volnum <= 3'd2;
                VOL4:
                        volnum <= 3'd3;
                VOL5:
                        volnum <= 3'd4;
                VOL6:
                        volnum <= 3'd5;
                VOL7:
                        volnum <= 3'd6;
                VOL8:
                        volnum <= 3'd7;
                default:
                        volnum <= 3'bXXX;
                endcase
        end

        // handling itself (sending data to sound module)
        always @(posedge cpu_clock)
        begin
                if( memreg_rd ) // memory read - sample data write
                begin
                        snd_wrtoggle <= ~snd_wrtoggle;
                        snd_datnvol  <= 1'b1; // sample data

                        if( !mode_8chans ) // 4 channel mode
                                snd_addr <= { 1'b0, a[9:8] };
                        else // 8 channel mode
                                snd_addr <= a[10:8];

                        snd_data <= din;
                end
                else if( volports_enabled && port_wr )
                begin
                        snd_wrtoggle <= ~snd_wrtoggle;
                        snd_datnvol  <= 1'b0; // volume data
                        snd_addr <= volnum;
                        snd_data <= din;
                end
        end






        //SPI (mp3, SD) interfaces

        assign sd_din = (a[5:0]==SD_RSTR) ? 8'hFF : din;
        assign mc_din = din;
        assign md_din = din;


        assign sd_start = p_sdsnd_wr | p_sdrst_rd;
        assign mc_start = p_mcsnd_wr;
        assign md_start = p_mdsnd_wr;


      always @(posedge cpu_clock, negedge rst_n)
      begin
                if( !rst_n ) // async reset
                begin
                        md_halfspeed <= 1'b0;
                        mc_speed     <= 2'b01;
                        mc_xrst      <= 1'b0;
                        mc_ncs       <= 1'b1;
                        sd_ncs       <= 1'b1;
                end
                else // clock
                begin
                        if( p_sctrl_wr )
                        begin
                                if( din[0] )
                                        sd_ncs       <= din[7];

                                if( din[1] )
                                        mc_ncs       <= din[7];

                                if( din[2] )
                                        mc_xrst      <= din[7];

                                if( din[3] )
                                        mc_speed[0]  <= din[7];

                                if( din[4] )
                                        md_halfspeed <= din[7];

                                if( din[5] )
                                        mc_speed[1]  <= din[7];

                        end
                end
      end


        // LED control
        always @(posedge cpu_clock, negedge rst_n)
        begin
                if( !rst_n )
                        led <= 1'b0;
                else
                begin
                        if( p_ledctr_wr )
                                led <= din[0];
                        else if( led_toggle )
                                led <= ~led;
                end

        end




        // DMA control
        //
        always @(posedge cpu_clock, negedge rst_n) // selection of modules
        begin
                if( !rst_n )
                        dma_module_select <= DMA_NONE_SELECTED;
                else if( p_dmamod_wr )
                        dma_module_select <= din[2:0];
        end
        //
        always @* dma_din_modules = din; // translate Z80 bus out to all DMA modules
        //
        always @* // select modules by individual signals
        begin
                dma_select_zx = 1'b0;
                //dma_select_... = 1'b0;

                case( dma_module_select )
                DMA_MODULE_ZX:
                        dma_select_zx = 1'b1;
                //DMA_MODULE_...:
                //      dma_select_... = 1'b1;
                endcase
        end
        //
        always @* dma_wrstb = p_dmaports_wr; // translate dma write strobe
        //
        always @* dma_regsel = a[1:0];
        //
        always @* // route data from modules to the common module bus
        begin
                case( dma_regsel )
                DMA_MODULE_ZX:
                        dma_dout_modules <= dma_dout_zx;
                //DMA_MODULE_...:
                //      dma_dout_modules <= dma_dout_...;
                default:
                        dma_dout_modules <= 8'bxxxxxxxx;
                endcase
        end


endmodule