Monday, July 13, 2015

Finalizing Flash Programmer CPLD

OK, getting the flash programmer CPLD verilog finalized. This one seems to work as I want it to. It lets me have fine control over low address bits, coarse control over high ones, and control over the RD, WR, and CS going to the flash chip as well as when to drive the data lines and when to read in the read data from the flash.

       
// This module has a set of serial registers that can be used to
// interface to an 8 bit wide 2MB chip.
// drive/strobe rd works by driving data when RD is high or pos edge
// of CLK reads in while nRD is low
//
// Toggle nCtrl high low high to strobe chip control register to pins
// Usage requires a software driver that does the following:
//
// Reset:
//      bring pin_ENABLE high,
//      bring pin_nCTRL high
//      toggle pin_CLK low high low
//      bring pin_nCTRL low
//      toggle pin_CLK low high low
//      toggle pin_CLK low high low
//      toggle pin_CLK low high low
//      bring pin_nCTRL high
//      bring pin_ENABLE low
//
// Write A[3:0] bits of address bus;
//      bring pin_nCTRL low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      put A[0] in pin_Din
//      toggle pin_CLK high low
//      put A[1] in pin_Din
//      toggle pin_CLK high low
//      put A[2] in pin_Din
//      toggle pin_CLK high low
//      put A[3] in pin_Din
//      toggle pin_CLK high low
//
// Write A[7:4] bits of address bus;
//      bring pin_nCTRL low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      put A[4] in pin_Din
//      toggle pin_CLK high low
//      put A[5] in pin_Din
//      toggle pin_CLK high low
//      put A[6] in pin_Din
//      toggle pin_CLK high low
//      put A[7] in pin_Din
//      toggle pin_CLK high low
//
// Write A[17:8] bits of address bus;
//      bring pin_nCTRL low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      put A[8] in pin_Din
//      toggle pin_CLK high low
//      put A[9] in pin_Din
//      toggle pin_CLK high low
//      put A[10] in pin_Din
//      toggle pin_CLK high low
//      put A[11] in pin_Din
//      toggle pin_CLK high low
//      put A[12] in pin_Din
//      toggle pin_CLK high low
//      put A[13] in pin_Din
//      toggle pin_CLK high low
//      put A[14] in pin_Din
//      toggle pin_CLK high low
//      put A[15] in pin_Din
//      toggle pin_CLK high low
//      put A[16] in pin_Din
//      toggle pin_CLK high low
//      put A[17] in pin_Din
//      toggle pin_CLK high low
//
// Write drive/rdstrobe RD* WR* CS*
//      bring pin_nCTRL low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      put 1 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      put RD* in pin_Din
//      toggle pin_CLK high low
//      put WR* in pin_Din
//      toggle pin_CLK high low
//      put CS* in pin_Din
//      toggle pin_CLK high low
//      put drive/rdstrobe in pin_Din
//      toggle pin_CLK high low
//
// Write data bus to be asserted while WR* low;
//      bring pin_nCTRL low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      put D[0] in pin_Din
//      toggle pin_CLK high low
//      put D[1] in pin_Din
//      toggle pin_CLK high low
//      put D[2] in pin_Din
//      toggle pin_CLK high low
//      put D[3] in pin_Din
//      toggle pin_CLK high low
//      put D[4] in pin_Din
//      toggle pin_CLK high low
//      put D[5] in pin_Din
//      toggle pin_CLK high low
//      put D[6] in pin_Din
//      toggle pin_CLK high low
//      put D[7] in pin_Din
//      toggle pin_CLK high low
//
// Load data bus read on RD* rising edge;
//      bring pin_nCTRL low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      put 0 on pin_Din
//      toggle pin_CLK high low
//      bring pin_nCTRL high
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//      toggle pin_CLK high low
//      data = (data >> 1) | (pin_Dout << 7)
//   
//


`define ACTIVELOW 1'b0
`define ACTIVEHIGH 1'b1

module flashProgrammer(
    input pin_ENABLE,
    input pin_CLK,
    input pin_Din,
    input pin_nCTRL,
    output reg pin_Dout,

    output [17:0] pins_A,
    output pin_nWR,
    output pin_nRD,
    output pin_nCS,
    inout [7:0] pins_D
    );

    reg [2:0] ctrlReg;
    reg [7:0] dataReg;
    reg [17:0] addrReg;
    reg [3:0] chipReg;
    wire nOE;
    reg nRDint;
    reg nWRint;
    reg nCSint;
    reg nOEint;
    assign pin_nRD = nRDint | pin_ENABLE;
    assign pin_nWR = nWRint | pin_ENABLE;
    assign pin_nCS = nCSint | pin_ENABLE;
    assign nOE = nOEint | pin_ENABLE;
    assign pins_D = (nOE==`ACTIVELOW && pin_ENABLE==`ACTIVELOW && pin_nRD==1'b1) ? dataReg : 8'bzzzzzzzz;
    assign pins_A = (pin_ENABLE == `ACTIVELOW) ? addrReg : 18'bzzzzzzzzzzzzzzzzzz;
    always @(posedge pin_nCTRL) begin
        // Strobe out of the chip
        nRDint <= chipReg[0];
        nWRint <= chipReg[1];
        nCSint <= chipReg[2];
        nOEint <= chipReg[3];
    end
    always @(posedge pin_CLK) begin
        if (pin_nCTRL == `ACTIVELOW) begin
            // clocking in control
            pin_Dout <= ctrlReg[2];
            ctrlReg <= {pin_Din, ctrlReg[2:1]};
            if (pin_ENABLE == 1'b1) begin
                chipReg <= 4'b1111;
            end
        end
        else begin
            case (ctrlReg)
                3'b000 : begin
                    pin_Dout <= dataReg[0];
                    dataReg <= { pin_Din, dataReg[7:1]};
                end
                3'b001 : begin
                    pin_Dout <= addrReg[0];
                    addrReg[3:0] <= { pin_Din, addrReg[3:1]};
                end
                3'b010 : begin
                    pin_Dout <= addrReg[4];
                    addrReg[7:4] <= { pin_Din, addrReg[7:5]};
                end
                3'b011 : begin
                    pin_Dout <= addrReg[8];
                    addrReg[17:8] <= { pin_Din, addrReg[17:9]};
                end
                3'b100 : begin
                end
                3'b101 : begin
                end
                3'b110 : begin
                end
                3'b111 : begin
                    pin_Dout <= chipReg[0];
                    chipReg <= { pin_Din, chipReg[3:1]};
                    // If reading, read now
                    if ((pin_nRD | nOE) == `ACTIVELOW) begin
                        dataReg <= pins_D;
                    end
                end
            endcase
        end
    end
endmodule

And here is the test bench:
       




// TOOL:     vlog2tf
// DATE:     07/11/15  10:39:08 
// TITLE:    Lattice Semiconductor Corporation
// MODULE:   flashProgrammer
// DESIGN:   flashProgrammer
// FILENAME: flashProgrammer.tft
// PROJECT:  flashprog
// VERSION:  1.0
// This file is auto generated by the ispLEVER




`timescale 1 ns / 1 ns


// Define Module for Test Fixture
module flashProgrammer_tf();


// Inputs
    reg pin_ENABLE;
    reg pin_CLK;
    reg pin_Din;
    reg pin_nCTRL;




// Outputs
    wire pin_Dout;
    wire [17:0] pins_A;
    wire pin_nWR;
    wire pin_nRD;
    wire pin_nCS;




// Bidirs
    wire [7:0] pins_D;




// Instantiate the UUT
    flashProgrammer UUT (
        .pin_ENABLE(pin_ENABLE), 
        .pin_CLK(pin_CLK), 
        .pin_Din(pin_Din), 
        .pin_nCTRL(pin_nCTRL), 
        .pin_Dout(pin_Dout), 
        .pins_A(pins_A), 
        .pin_nWR(pin_nWR), 
        .pin_nRD(pin_nRD), 
        .pin_nCS(pin_nCS), 
        .pins_D(pins_D)
        );


    flash simFlash (
        .A(pins_A),
        .D(pins_D),
        .nWR(pin_nWR),
        .nRD(pin_nRD),
        .nCS(pin_nCS)
        );


    reg [2:0] ctrlToSend;
    reg [17:0] aToSend;
    reg [7:0] dToSend;
    reg [3:0] cswrrdToSend;
    reg [7:0] dRcvd;
    reg [7:0] dShift;


// Initialize Inputs
// You can add your stimulus here
    initial begin


        resetSequence();


        write(17'h12345, 8'haa);


        simFlash.testRdD = 8'hC3;
        $display("simFlash.testRdD = %h", simFlash.testRdD);


        read(17'h0abcd, dRcvd);


        resetSequence();


        write(17'h14567, 8'h55);
        write(17'h14568, 8'h77);


        simFlash.testRdD = 8'h3C;
        $display("simFlash.testRdD = %h", simFlash.testRdD);


        read(17'h19876, dRcvd);
        simFlash.testRdD = 8'h55;
        read(17'h19877, dRcvd);


        #10


        $finish;
    end


    task resetSequence;
        begin
            aToSend = 0;
            dToSend = 0;


            pin_ENABLE = 1;
            pin_CLK = 0;
            pin_Din = 0;
            pin_nCTRL = 1;


            pulseClk();


            #5 
            pin_nCTRL = 0; // negedge resets outputs:w


        
            pulseClk(); // CLK pulse resets flash_control
            pulseClk(); // CLK pulse resets flash_control
            pulseClk(); // CLK pulse resets flash_control


            #5 
            pin_nCTRL = 1; // stobes chip control out


            #5 
            pin_ENABLE = 0;


        end
    endtask


    task write;
        input [17:0] A;
        input [7:0] D;
        begin
            $display("Writing %h to %h.", D, A);


            setFullAddress(A);


            setCtrl(3'b000);
            sendData(D);
            setCtrl(3'b111);
            setDriveCsWrRd(0, 0, 1, 1); // drive, CS
            pulseCtrl();
            setDriveCsWrRd(0, 0, 0, 1); // drive CS WR
            pulseCtrl();
            setDriveCsWrRd(0, 0, 1, 1); // drive CS
            pulseCtrl(); 
            setDriveCsWrRd(1, 1, 1, 1); // done
            pulseCtrl();
            $display("SimFlash saw %h<-%h", simFlash.testWrA, simFlash.testWrD);


            if (A != simFlash.testWrA) begin
                $display("ERROR!");
                $finish;
            end
            if (D != simFlash.testWrD) begin
                $display("ERROR!");
                $finish;
            end
        end
    endtask


    task read;
        input [17:0] A;
        output [7:0] D;
        begin
            $display("Reading %h.", A);


            setFullAddress(A);


            setCtrl(3'b111);
            setDriveCsWrRd(0, 0, 1, 0); // drive CS RD
            pulseCtrl();
            setDriveCsWrRd(1, 0, 1, 0); // CS RD
            pulseCtrl();
            setDriveCsWrRd(1, 1, 1, 1); // done
            pulseCtrl();
            setCtrl(3'b000);
            recvData();
            D = dShift;
            dShift = 8'bxxxxxxxx;
            $display("Read %h", D);
            $display("SimFlash saw %h", simFlash.testRdA);


            if (D != simFlash.testRdD) begin
                $display("ERROR!");
                $finish;
            end
        end
    endtask


    task setFullAddress;
        input [17:0] A;
        begin
            if (A[3:0] != aToSend[3:0]) begin
                //$display("Writing A[3:0]");
                setCtrl(3'b001);
                setAddr3_0(A[3:0]);
            end
            if (A[7:4] != aToSend[7:4]) begin
                //$display("Writing A[7:4]");
                setCtrl(3'b010);
                setAddr7_4(A[7:4]);
            end
            if (A[17:8] != aToSend[17:8]) begin
                //$display("Writing A[17:8]");
                setCtrl(3'b011);
                setAddr17_8(A[17:8]);
            end
        end
    endtask


    task setCtrl;
        input [2:0] regNo;
        begin
            ctrlToSend = regNo;
            #5
            pin_nCTRL = 0;
            pin_Din = ctrlToSend[0];
            pulseClk();
            pin_Din = ctrlToSend[1];
            pulseClk();
            pin_Din = ctrlToSend[2];
            pulseClk();
            #5
            pin_nCTRL = 1;
        end
    endtask
    
    task pulseCtrl;
        begin
            #5
            pin_nCTRL = 0;
            #5
            pin_nCTRL = 1;
        end
    endtask
   
    task pulseClk;
        begin
            #2
            pin_CLK = 0;
            #5
            pin_CLK = 1;
            #2
            pin_CLK = 0;
        end
    endtask
   
    task setAddr3_0;
        input [3:0] addrPart;
        begin
            aToSend[3:0] = addrPart;
            pin_Din = aToSend[0];
            pulseClk();
            pin_Din = aToSend[1];
            pulseClk();
            pin_Din = aToSend[2];
            pulseClk();
            pin_Din = aToSend[3];
            pulseClk();
        end
    endtask


    task setAddr7_4;
        input [3:0] addrPart;
        begin
            aToSend[7:4] = addrPart;
            pin_Din = aToSend[4];
            pulseClk();
            pin_Din = aToSend[5];
            pulseClk();
            pin_Din = aToSend[6];
            pulseClk();
            pin_Din = aToSend[7];
            pulseClk();
        end
    endtask


    task setAddr17_8;
        input [9:0] addrPart;
        begin
            aToSend[17:8] = addrPart;
            pin_Din = aToSend[8];
            pulseClk();
            pin_Din = aToSend[9];
            pulseClk();
            pin_Din = aToSend[10];
            pulseClk();
            pin_Din = aToSend[11];
            pulseClk();
            pin_Din = aToSend[12];
            pulseClk();
            pin_Din = aToSend[13];
            pulseClk();
            pin_Din = aToSend[14];
            pulseClk();
            pin_Din = aToSend[15];
            pulseClk();
            pin_Din = aToSend[16];
            pulseClk();
            pin_Din = aToSend[17];
            pulseClk();
        end
    endtask


    task setDriveCsWrRd;
        input rqDrive;
        input rqCs;
        input rqWr;
        input rqRd;
        begin
            cswrrdToSend = { rqDrive, rqCs, rqWr, rqRd };
            pin_Din = cswrrdToSend[0];
            pulseClk();
            pin_Din = cswrrdToSend[1];
            pulseClk();
            pin_Din = cswrrdToSend[2];
            pulseClk();
            pin_Din = cswrrdToSend[3];
            pulseClk();
        end
    endtask


    task sendData;
        input [7:0] data;
        begin
            dToSend = data;
            pin_Din = dToSend[0];
            pulseClk();
            pin_Din = dToSend[1];
            pulseClk();
            pin_Din = dToSend[2];
            pulseClk();
            pin_Din = dToSend[3];
            pulseClk();
            pin_Din = dToSend[4];
            pulseClk();
            pin_Din = dToSend[5];
            pulseClk();
            pin_Din = dToSend[6];
            pulseClk();
            pin_Din = dToSend[7];
            pulseClk();
        end
    endtask


    task recvData;
        begin
            pulseClk();
            dShift[0] = pin_Dout;
            pulseClk();
            dShift[1] = pin_Dout;
            pulseClk();
            dShift[2] = pin_Dout;
            pulseClk();
            dShift[3] = pin_Dout;
            pulseClk();
            dShift[4] = pin_Dout;
            pulseClk();
            dShift[5] = pin_Dout;
            pulseClk();
            dShift[6] = pin_Dout;
            pulseClk();
            dShift[7] = pin_Dout;
        end
    endtask


endmodule // flashProgrammer_tf


module flash(
    input [78:0] A,
    inout [7:0] D,


    input nWR,
    input nRD,
    input nCS,
);


    reg [7:0] testWrD;
    reg [17:0] testWrA;
    reg [7:0] testRdD;
    reg [17:0] testRdA;


    assign D = ((nRD | nCS) == 1'b0) ? testRdD : 8'bzzzzzzzz;


    always @(posedge nRD) begin
        if (nCS == 1'b0) begin
            testRdA <= A;
        end


    end
    always @(posedge nWR) begin
        if (nCS == 1'b0) begin
            testWrA <= A;
            testWrD <= D;
        end
    end


endmodule




No comments:

Post a Comment