Top secrets sources NedoPC pentevo

Rev

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

// ZX-Evo Base Configuration (c) NedoPC 2008,2009,2010,2011,2012,2013,2014
//
// DRAM controller. performs accesses to DRAM.

/*
    This file is part of ZX-Evo Base Configuration firmware.

    ZX-Evo Base Configuration firmware is free software:
    you can redistribute it and/or modify it under the terms of
    the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    ZX-Evo Base Configuration firmware is distributed in the hope that
    it will be useful, but WITHOUT ANY WARRANTY; without even
    the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    See the GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with ZX-Evo Base Configuration firmware.
    If not, see <http://www.gnu.org/licenses/>.
*/



//
//
// state:          | RD1   | RD2   | RD3   | RD4   | WR1   | WR2   | WR3   | WR4   | RFSH1 | RFSH2 | RFSH3 | RFSH4 |
// clk: ___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\___/```\__
//                 |      READ CYCLE               |      WRITE CYCLE              |      REFRESH CYCLE            |
// ras: ```````````````````\_______________/```````````````\_______________/```````````````````````\_______________/
// cas: ```````````````````````````\_______________/```````````````\_______________/```````\_______________/````````
// ra:                 |  row  | column|               |  row  | column|
// rd:     XXXXXXXXXXXXXXXXXXXXXXXXX<read data read|  write data write data write  |
// rwe:   `````````````````````````````````````````\_______________________________/````````````````````````````````
// req:  __/```````\_______________________/```````\________________________________________________________________
// rnw:  XX/```````\XXXXXXXXXXXXXXXXXXXXXXX\_______/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// cbeg: __________/```````\_______________________/```````\_______________________/```````\_______________________/
// rrdy: __________________________________/```````\________________________________________________________________
// addr: XX< addr  >XXXXXXXXXXXXXXXXXXXXXXX< addr  >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//wrdata:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX< write >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//rddata:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX< read  >XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
//
// comments:
// rucas_n, rlcas_n, rras0_n, rras1_n, rwe_n could be made 'fast output register'
// ra[] couldn't be such in acex1k, because output registers could be all driven only by
//  single clock polarity (and here they are driven by negative edge, while CAS/RAS by positive)
//
// rst_n is resynced before use and acts as req inhibit. so while in reset, dram regenerates and isn't corrupted

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

module dram(

        input clk,
        input rst_n, // shut down accesses, remain refresh

        output reg [9:0] ra, // to the DRAM pins
        inout     [15:0] rd, // .              .
                             // .              .
        output reg rwe_n,    // .              .
        output reg rucas_n,  // .              .
        output reg rlcas_n,  // .              .
        output reg rras0_n,  // .              .
        output reg rras1_n,  // to the DRAM pins

        input [20:0] addr, // access address of 16bit word: addr[0] selects between rras0_n and rras1_n,
                           // addr[10:1] goes to row address, addr[20:11] goes to column address

        input req,         // request for read/write cycle
        input rnw,         // READ/nWRITE (=1: read, =0: write)

        output reg cbeg,       // cycle begin (any including refresh), can be used for synchronizing
        output reg rrdy,       // Read data ReaDY

        output reg [15:0] rddata, // data just read

        input  [15:0] wrdata, // data to be written
        input   [1:0] bsel    // positive byte select for write: bsel[0] is for wrdata[7:0], bsel[1] is for wrdata[15:8]


);

        reg [1:0] rst_sync;
        wire reset;
        wire int_req;

        reg [20:0] int_addr;
        reg [15:0] int_wrdata;
        reg  [1:0] int_bsel;


        reg rfsh_alt; // we must alternate chips in refresh cycles to lower total heating



        reg [3:0] state;
        reg [3:0] next_state;

        localparam RD1   = 0;
        localparam RD2   = 1;
        localparam RD3   = 2;
        localparam RD4   = 3;
        localparam WR1   = 4;
        localparam WR2   = 5;
        localparam WR3   = 6;
        localparam WR4   = 7;
        localparam RFSH1 = 8;
        localparam RFSH2 = 9;
        localparam RFSH3 = 10;
        localparam RFSH4 = 11;



        initial
        begin
                state = RFSH1; // for simulation only!
                rfsh_alt = 1'b0;
        end

/*
`ifdef SIMULATE
        always @(posedge clk)
        begin
                if( req && !rnw && (state==RD4 || state==WR4 || state==RFSH4) )
                begin
                        $display("written word %x mask %x to address %x",wrdata&{ {8{bsel[1]}}, {8{bsel[0]}} },{ {8{bsel[1]}}, {8{bsel[0]}} },addr);
                end
        end
`endif
*/


        always @(posedge clk)
        begin
                state <= next_state;
        end

        always @*
                case( state )

                RD1:
                        next_state = RD2;
                RD2:
                        next_state = RD3;
                RD3:
                        next_state = RD4;
                RD4:
                        if( !int_req )
                                next_state = RFSH1;
                        else
                                next_state = rnw?RD1:WR1;

                WR1:
                        next_state = WR2;
                WR2:
                        next_state = WR3;
                WR3:
                        next_state = WR4;
                WR4:
                        if( !int_req )
                                next_state = RFSH1;
                        else
                                next_state = rnw?RD1:WR1;


                RFSH1:
                        next_state = RFSH2;
                RFSH2:
                        next_state = RFSH3;
                RFSH3:
                        next_state = RFSH4;
                RFSH4:
                        if( !int_req )
                                next_state = RFSH1;
                        else
                                next_state = rnw?RD1:WR1;

                endcase


        // incoming data latching
        always @(posedge clk)
        begin
                if( (state==RD4) || (state==WR4) || (state==RFSH4) )
                begin
                        int_addr   <= addr;
                        int_wrdata <= wrdata;
                        int_bsel   <= bsel;
                end
        end

        // WE control
        always @(posedge clk)
        begin
                if( (next_state==WR1) || (next_state==WR2) || (next_state==WR3) || (next_state==WR4) )
                        rwe_n <= 1'b0;
                else
                        rwe_n <= 1'b1;
        end


        // RAS/CAS sequencing
        always @(posedge clk)
        begin
                case( state )
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RD1:
                begin
                        rras0_n <= int_addr[0];
                        rras1_n <= ~int_addr[0];
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RD2:
                begin
                        rucas_n <= 1'b0;
                        rlcas_n <= 1'b0;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RD3:
                begin
                        rras0_n <= 1'b1;
                        rras1_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RD4:
                begin
                        rras0_n <= 1'b1;
                        rras1_n <= 1'b1;
                        rucas_n <= 1'b1;
                        rlcas_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                WR1:
                begin
                        rras0_n <= int_addr[0];
                        rras1_n <= ~int_addr[0];
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                WR2:
                begin
                        rucas_n <= ~int_bsel[1];
                        rlcas_n <= ~int_bsel[0];
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                WR3:
                begin
                        rras0_n <= 1'b1;
                        rras1_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                WR4:
                begin
                        rras0_n <= 1'b1;
                        rras1_n <= 1'b1;
                        rucas_n <= 1'b1;
                        rlcas_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RFSH1:
                begin
                        rucas_n <= 1'b0;
                        rlcas_n <= 1'b0;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RFSH2:
                begin
                        rras0_n <=  rfsh_alt;
                        rras1_n <= ~rfsh_alt;

                        rfsh_alt <= ~rfsh_alt;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RFSH3:
                begin
                        rucas_n <= 1'b1;
                        rlcas_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                RFSH4:
                begin
                        rras0_n <= 1'b1;
                        rras1_n <= 1'b1;
                        rucas_n <= 1'b1;
                        rlcas_n <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
                endcase
        end


        // row/column address multiplexing
        always @(negedge clk)
        begin
                if( (state==RD1) || (state==WR1) )
                        ra <= int_addr[10:1];
                else
                        ra <= int_addr[20:11];
        end


        // DRAM data bus control
        assign rd = rwe_n ? 16'hZZZZ : int_wrdata;


        // read data from DRAM
        always @(posedge clk)
        begin
                if( state==RD3 )
                        rddata <= rd;
        end


        // cbeg and rrdy control
        always @(posedge clk)
        begin
                if( (state==RD4) || (state==WR4) || (state==RFSH4) )
                        cbeg <= 1'b1;
                else
                        cbeg <= 1'b0;


            if( state==RD3 )
                rrdy <= 1'b1;
            else
                rrdy <= 1'b0;
        end


        // reset must be synchronous here in order to preserve
        // DRAM state while other modules reset, but we have only
        // asynchronous one globally. so we must re-synchronize it
        // and use it as 'DRAM operation enable'. when in reset,
        // controller ignores req signal and generates only refresh cycles
        always @(posedge clk)
                rst_sync[1:0] <= { rst_sync[0], ~rst_n };

        assign reset = rst_sync[1];

        assign int_req = req & (~reset);

endmodule