`timescale 1ns / 1ps
module S5443_3_tb;

parameter CLK_PERIOD = 8.13; // Clock period in ns




reg Clk_i;
reg Rst_i;
reg [10:0] SmcAddr_i;
reg [15:0]SmcData_i;
reg SmcAre_i;
reg SmcAwe_i;
wire SmcAmsN_i;
wire [1:0] SmcBe_i;
reg SmcAoe_i;

reg [31:0] tb_cnt;
wire [15:0] smcData;
reg mosi1reg;
//***********************************************
//	           SPI0 Adresses
//***********************************************

// Address map for SPI0
localparam [10:0] BaseAddr0 = 11'h0;
localparam [10:0] Spi0CtrlAddr = BaseAddr0;
localparam [10:0] Spi0ClkAddr = (BaseAddr0 + 4)>>1;
localparam [10:0] Spi0CsDelayAddr = (BaseAddr0 + 8)>>1;
localparam [10:0] Spi0CsCtrlAddr = (BaseAddr0 + 12)>>1;
localparam [10:0] Spi0TxFifoCtrlAddr = (BaseAddr0 + 16)>>1;
localparam [10:0] Spi0RxFifoCtrlAddr = (BaseAddr0 + 20)>>1;
localparam [10:0] Spi0TxFifoAddrL = (BaseAddr0 + 24)>>1;
localparam [10:0] Spi0TxFifoAddrM = (BaseAddr0 + 26)>>1;
localparam [10:0] Spi0RxFifoAddrL = (BaseAddr0 + 28)>>1;
localparam [10:0] Spi0RxFifoAddrM = (BaseAddr0 + 30)>>1;

// Data for SPI0CtrlReg 


//***********************************************
//	           SPI0 Ctrl Reg Data
//***********************************************
localparam SpiEn0 = 1'b1;//1 for enable, 0 for disable
localparam ClockPhase0 = 1'b0;//
localparam ClockPolarity0 = 1'b0;//0 for active high, 1 for active low
localparam Assel0 = 1'b1;//0 for software control, 1 for hardware control
localparam SelSt0 = 1'b1; //1 - assert slave select(low), 0 - deassert slave select(high)
localparam Size0 = 2'd1; //0 - 8 bits, 1 - 16 bits, 2 - 24 bits, 3 - 32 bits
localparam Mode0 = 1'b0; // 1 - 4 Mosi, 0 - 1 Mosi
localparam LSBF0 = 1'b0; // 1 - LSB first, 0 - MSB first

localparam [15:0] Spi0CtrlRegData = {8'h0,LSBF0, Mode0, Size0, SelSt0, Assel0, ClockPolarity0, ClockPhase0, SpiEn0};


//***********************************************
//	           SPI0 Clk Reg Data
//***********************************************

localparam Div = 4'd1; // Custom divider value(input clock frequency = 80 MHz)
localparam Mux0 = 1'b1; // 0 - input clock, 1 - MMCM output clock
localparam Mux1 = 3'd0; // MMCM output clock number

localparam Spi0ClkRegData = {8'h0, Mux1, Mux0, Div};


//***********************************************
//	           SPI0 Cs Delay Reg Data
//***********************************************
localparam Lag0 = 1'b0; //Extended SPI clock lag control, 0 - Disable, 1 - Enable
localparam Lead0 = 1'b0; //Extended SPI clock lead control, 0 - Disable, 1 - Enable
localparam Stop0 = 6'd1; //Number of clock cycles to wait after CS is deasserted

localparam [15:0] Spi0CsDelayRegData = {8'h0, Stop0, Lead0, Lag0};

//***********************************************
//	           SPI0 Cs Ctrl Reg Data
//***********************************************
localparam CS0 = 1'b1; // 1 - device selected, 0 - device deselected
localparam CS1 = 1'b1; // 1 - device selected, 0 - device deselected

localparam [15:0] Spi0CsCtrlRegData = {14'h0, CS1, CS0};

//***********************************************
//	           SPI0 Tx Fifo Ctrl Reg Data
//***********************************************
localparam RstTxFifo0 = 1'b1; // 1 - Reset Tx FIFO, 0 - Normal operation
// at least 5 clock cycles of a slow clock

localparam [15:0] Spi0TxFifoCtrlRegDataRstOn = {15'h0, RstTxFifo0};
localparam [15:0] Spi0TxFifoCtrlRegDataRstOff = {15'h0, 1'b0};

//***********************************************
//	           SPI0 Rx Fifo Ctrl Reg Data
//***********************************************
localparam RstRxFifo0 = 1'b1; // 1 - Reset Rx FIFO, 0 - Normal operation

localparam [15:0] Spi0RxFifoCtrlRegDataRstOn = {15'h0, RstRxFifo0};
localparam [15:0] Spi0RxFifoCtrlRegDataRstOff = {15'h0, 1'b0};

//***********************************************
//	           SPITXRX Enable Register
//***********************************************
localparam SpiTxRxEn0 = 1'b1;
localparam SpiTxRxEn1 = 1'b0;
localparam SpiTxRxEn2 = 1'b0;
localparam SpiTxRxEn3 = 1'b0;
localparam SpiTxRxEn4 = 1'b0;
localparam SpiTxRxEn5 = 1'b0;
localparam SpiTxRxEn6 = 1'b0;

localparam [15:0] SpiTxRxEnRegData = {8'h0, SpiTxRxEn6, SpiTxRxEn5, SpiTxRxEn4, SpiTxRxEn3, SpiTxRxEn2, SpiTxRxEn1, SpiTxRxEn0};



//***********************************************
//	           GPIO Reg Data
//***********************************************
localparam RstForSbTmsg = 1'b1; // 1 - Reset for SB TMSG, 0 - Normal operation


localparam [15:0] GPIORegDataRstOn = {15'h0, RstForSbTmsg};
localparam [15:0] GPIORegDataRstOff = {15'h0, 1'b0};


//***********************************************
//	           SPI1HEADERS
//***********************************************
localparam [10:0] BaseAddr1 = 11'h50;
localparam [10:0] Spi1CtrlAddr = BaseAddr1;
localparam [10:0] Spi1ClkAddr = BaseAddr1 + 4;
localparam [10:0] Spi1CsDelayAddr = BaseAddr1 + 8;
localparam [10:0] Spi1CsCtrlAddr = BaseAddr1 + 12;
localparam [10:0] Spi1TxFifoCtrlAddr = BaseAddr1 + 16;
localparam [10:0] Spi1RxFifoCtrlAddr = BaseAddr1 + 20;
localparam [10:0] Spi1TxFifoAddr = BaseAddr1 + 24;
localparam [10:0] Spi1RxFifoAddr = BaseAddr1 + 28;

//***********************************************
//	           SPI2HEADERS
//***********************************************
localparam [10:0] BaseAddr2 = 11'hF0;
localparam [10:0] Spi2CtrlAddr = BaseAddr2;
localparam [10:0] Spi2ClkAddr = BaseAddr2 + 4;
localparam [10:0] Spi2CsDelayAddr = BaseAddr2 + 8;
localparam [10:0] Spi2CsCtrlAddr = BaseAddr2 + 12;
localparam [10:0] Spi2TxFifoCtrlAddr = BaseAddr2 + 16;
localparam [10:0] Spi2RxFifoCtrlAddr = BaseAddr2 + 20;
localparam [10:0] Spi2TxFifoAddr = BaseAddr2 + 24;
localparam [10:0] Spi2RxFifoAddr = BaseAddr2 + 28;

//***********************************************
//	           SPI3HEADERS
//***********************************************
localparam [10:0] BaseAddr3 = 11'h140;
localparam [10:0] Spi3CtrlAddr = BaseAddr3;
localparam [10:0] Spi3ClkAddr = BaseAddr3 + 4;
localparam [10:0] Spi3CsDelayAddr = BaseAddr3 + 8;
localparam [10:0] Spi3CsCtrlAddr = BaseAddr3 + 12;
localparam [10:0] Spi3TxFifoCtrlAddr = BaseAddr3 + 16;
localparam [10:0] Spi3RxFifoCtrlAddr = BaseAddr3 + 20;
localparam [10:0] Spi3TxFifoAddr = BaseAddr3 + 24;
localparam [10:0] Spi3RxFifoAddr = BaseAddr3 + 28;

//***********************************************
//	           SPI4HEADERS
//***********************************************
localparam [10:0] BaseAddr4 = 11'h190;
localparam [10:0] Spi4CtrlAddr = BaseAddr4;
localparam [10:0] Spi4ClkAddr = BaseAddr4 + 4;
localparam [10:0] Spi4CsDelayAddr = BaseAddr4 + 8;
localparam [10:0] Spi4CsCtrlAddr = BaseAddr4 + 12;
localparam [10:0] Spi4TxFifoCtrlAddr = BaseAddr4 + 16;
localparam [10:0] Spi4RxFifoCtrlAddr = BaseAddr4 + 20;
localparam [10:0] Spi4TxFifoAddr = BaseAddr4 + 24;
localparam [10:0] Spi4RxFifoAddr = BaseAddr4 + 28;

//***********************************************
//	           SPI5HEADERS
//***********************************************
localparam [10:0] BaseAddr5 = 11'h1E0;
localparam [10:0] Spi5CtrlAddr = BaseAddr5;
localparam [10:0] Spi5ClkAddr = BaseAddr5 + 4;
localparam [10:0] Spi5CsDelayAddr = BaseAddr5 + 8;
localparam [10:0] Spi5CsCtrlAddr = BaseAddr5 + 12;
localparam [10:0] Spi5TxFifoCtrlAddr = BaseAddr5 + 16;
localparam [10:0] Spi5RxFifoCtrlAddr = BaseAddr5 + 20;
localparam [10:0] Spi5TxFifoAddr = BaseAddr5 + 24;
localparam [10:0] Spi5RxFifoAddr = BaseAddr5 + 28;


//***********************************************
//	           SPI5HEADERS
//***********************************************
localparam [10:0] BaseAddr6 = 11'h230;
localparam [10:0] Spi6CtrlAddr = BaseAddr6;
localparam [10:0] Spi6ClkAddr = BaseAddr6 + 4;
localparam [10:0] Spi6CsDelayAddr = BaseAddr6 + 8;
localparam [10:0] Spi6CsCtrlAddr = BaseAddr6 + 12;
localparam [10:0] Spi6TxFifoCtrlAddr = BaseAddr6 + 16;
localparam [10:0] Spi6RxFifoCtrlAddr = BaseAddr6 + 20;
localparam [10:0] Spi6TxFifoAddr = BaseAddr6 + 24;
localparam [10:0] Spi6RxFifoAddr = BaseAddr6 + 28;


//***********************************************
//	           SPITXRX Enable Reg Adress
//***********************************************

localparam SpiTxRxEnAddr = 11'h780;

//***********************************************
//	           GPIO Reg Adress
//***********************************************

localparam GPIOAddr = 11'hFF0;

//***********************************************
//	           ASSIGNS
//***********************************************
assign SmcBe_i = (tb_cnt >0 && tb_cnt <=44) ? 2'b00 : 2'b11;
assign SmcAmsN_i = (tb_cnt > 0 && tb_cnt <= 44) ? 1'b0 : 1'b1;
assign smcData = SmcData_i;
assign mosi1_io = (!Mode0) ? mosi0_o : 1'bz;

//***********************************************
//	           CLOCK GENERATION
//***********************************************

always #(CLK_PERIOD/2) Clk_i = ~Clk_i;

    S5443_3Top uut (
        .Clk123_i(Clk_i), 
        .SmcAddr_i(SmcAddr_i), 
        .SmcData_io(smcData), 
        .SmcAwe_i(SmcAwe_i), 
        .SmcAmsN_i(SmcAmsN_i), 
        .SmcAre_i(SmcAre_i), 
        .SmcBe_i(SmcBe_i), 
        .SmcAoe_i(SmcAoe_i), 
        .Led_o(), 
        .Mosi0_o(mosi0_o), 
        .Mosi1_io(mosi1_io), 
        .Mosi2_o(), 
        .Mosi3_o(), 
        .Ss_o(), 
        .SsFlash_o(), 
        .Sck_o(), 
        .SpiRst_o(), 
        .LD_o()
    );




always @(posedge Clk_i) begin 
    if (Rst_i) begin
        SmcAwe_i <= 1'b1;
    end
    else begin 
        if (tb_cnt > 0 && tb_cnt <= 44) begin 
            if (tb_cnt % 2 != 0) begin 
                SmcAwe_i <= 1'b1;
            end
            else begin 
                SmcAwe_i <= 1'b0;
            end
        end
    end
end

    




always @(posedge Clk_i) begin 
    if (Rst_i) begin 
        SmcAddr_i <= 0;
    end
    else begin
        if (tb_cnt < 27) begin
        case (tb_cnt)
        0: begin 
            SmcAddr_i <= BaseAddr0;
        end
        3: begin 
            SmcAddr_i <= Spi0ClkAddr;
        end
        5: begin 
            SmcAddr_i <= Spi0CsDelayAddr;
        end
        7: begin 
            SmcAddr_i <= Spi0CsCtrlAddr;
        end
        9: begin 
            SmcAddr_i <= Spi0TxFifoCtrlAddr;
        end
        11: begin 
            SmcAddr_i <= Spi0RxFifoCtrlAddr;
        end
        19 : begin 
            SmcAddr_i <= Spi0TxFifoCtrlAddr;
        end
        21 : begin 
            SmcAddr_i <= Spi0RxFifoCtrlAddr;
        end
        23 : begin 
            SmcAddr_i <= SpiTxRxEnAddr;
        end
        endcase
        end
        else begin 
            if (tb_cnt % 2 != 0) begin 
                SmcAddr_i <= Spi0TxFifoAddrL;
            end
            else begin 
                SmcAddr_i <= Spi0TxFifoAddrM;
            end
        end
    end
end


always @(posedge Clk_i) begin 
    if (Rst_i) begin 
        SmcData_i <= 16'h0;
    end
    else begin
        if (tb_cnt < 27 ) begin  
            case (tb_cnt)
            0 : begin 
                SmcData_i <= Spi0CtrlRegData;
            end
            3 : begin 
                SmcData_i <= Spi0ClkRegData;
            end
            5 : begin 
                SmcData_i <= Spi0CsDelayRegData;
            end
            7 : begin 
                SmcData_i <= Spi0CsCtrlRegData;
            end
            9 : begin 
                SmcData_i <= Spi0TxFifoCtrlRegDataRstOn;
            end
            11 : begin 
                SmcData_i <= Spi0RxFifoCtrlRegDataRstOn;
            end
            19 : begin 
                SmcData_i <= Spi0TxFifoCtrlRegDataRstOff;
            end
            21 : begin 
                SmcData_i <= Spi0RxFifoCtrlRegDataRstOff;
            end
            23 : begin 
                SmcData_i <= SpiTxRxEnRegData;
            end
            endcase
        end
        else begin 
                SmcData_i <= $urandom_range(0, 16'hFFFF);
                // SmcData_i <= 16'hff00;
            end
    end
end

always @(posedge Clk_i) begin 
    if (Rst_i) begin 
        tb_cnt <= 0;
    end
    else begin 
        tb_cnt <= tb_cnt + 1;
    end
end

initial begin 
    Clk_i = 1'b0;
    Rst_i = 1'b1;
    SmcAre_i = 1'b1;
    SmcAoe_i = 1'b1;
    #(CLK_PERIOD*300) Rst_i = 1'b0;




end

endmodule

