//---------------------------------------------------------
// SDRAM TSOP86: XJEase device file
// SDRAM_TSOP86.xje Revision: 1.2
// (c)2001-2007 XJTAG Limited
//
// Disclaimer: XJTAG makes no guarantees whatsoever
// about this code.  You use it at your own risk ...
// This code requires XJTAG version 1.4 or later.
//
// This file tests Non-JTAG SDRAM using Test()(INT result)
//---------------------------------------------------------

DEVICE NAME := "SDRAM TSOP86"

  PINS
    DATA    := 56, 54, 53, 51, 50, 48, 47, 45,
               42, 40, 39, 37, 36, 34, 33, 31,
               85, 83, 82, 80, 79, 77, 76, 74,
               13, 11, 10, 8, 7, 5, 4, 2;
    CLK     := 68;
    CKE     := 67;
    DQM     := 59, 28, 71, 16;
    nCAS    := 18;
    nRAS    := 19;
    nWE     := 17;
    nCS     := 20;
    COMMAND := 20, 19, 18, 17;  // NCS, NRAS, NCAS, NWE
    ADDR    := 21, 24, 66, 65, 64, 63, 62, 61, 60, 27, 26, 25; // pin 21 not always connected
    BANK    := 23, 22;
  END;

  DISABLE DEVICE
    nCS := 1;
  END;

  TEST COVERAGE
    CLK     := OPEN HI LO;
    CKE     := OPEN HI LO;
    DQM     := SHORTS OPEN HI LO;
    ADDR    := SHORTS OPEN HI LO;
    BANK    := SHORTS OPEN HI LO;
    DATA    := SHORTS OPEN HI LO;
    COMMAND := SHORTS OPEN HI LO;
  END;

  FILES
    "memtestSDRAM.xje";
  END;

END;

//------------------------------------------------------------------------------------
// Constants & Static Data
//------------------------------------------------------------------------------------

// Make sure the column and row widths have been checked as they vary from chip to chip.
// Incorrect values can produce "bank failures" with a fully working device.
CONST INT COL_WIDTH      WIDTH 32 := 8;
CONST INT ROW_WIDTH      WIDTH 32 := 12;

CONST INT DATA_BUS_WIDTH WIDTH 32 := WIDTHOF(DATA);
CONST INT DQM_BUS_WIDTH  WIDTH 32 := WIDTHOF(DQM);
CONST INT BANK_BUS_WIDTH WIDTH 32 := WIDTHOF(BANK);
CONST INT CLK_BUS_WIDTH  WIDTH 32 := WIDTHOF(CLK);
CONST INT DQS_BUS_WIDTH  WIDTH 32 := 0;
CONST INT ADDR_WIDTH     WIDTH 32 := (ROW_WIDTH + COL_WIDTH + BANK_BUS_WIDTH);

CONST INT AP_BIT         WIDTH 32 := 10;
CONST INT SIZE_MB        WIDTH 32 := (1 << (BANK_BUS_WIDTH + ROW_WIDTH + COL_WIDTH)) * (DATA_BUS_WIDTH / 8) / 1048576;
CONST INT CAS_LATENCY    WIDTH 3  := 3;

CONST INT BURST_LENGTH_1 WIDTH 3  := 0b000;
CONST INT BURST_LENGTH_2 WIDTH 3  := 0b001;
CONST INT BURST_LENGTH_4 WIDTH 3  := 0b010;
CONST INT BURST_LENGTH_8 WIDTH 3  := 0b011;
CONST INT BURST_LENGTH   WIDTH 3  := BURST_LENGTH_1;

CONST INT BURST_TYPE_SEQ WIDTH 1  := 0b0;
CONST INT BURST_TYPE_INT WIDTH 1  := 0b1;
CONST INT BURST_TYPE     WIDTH 1  := BURST_TYPE_SEQ;

CONST INT CMD_DESELECT   WIDTH 4  := 0b1111;
CONST INT CMD_NOP        WIDTH 4  := 0b0111;
CONST INT CMD_BTERM      WIDTH 4  := 0b0110;
CONST INT CMD_READ       WIDTH 4  := 0b0101;
CONST INT CMD_WRITE      WIDTH 4  := 0b0100;
CONST INT CMD_ACTIVE     WIDTH 4  := 0b0011;
CONST INT CMD_PRE        WIDTH 4  := 0b0010;
CONST INT CMD_REF        WIDTH 4  := 0b0001;
CONST INT CMD_MODE       WIDTH 4  := 0b0000;

CONST INT CLK_LO         WIDTH CLK_BUS_WIDTH := 0;
CONST INT CLK_HI         WIDTH CLK_BUS_WIDTH := ~0[CLK_BUS_WIDTH-1..0];

CONST INT DEBUG          WIDTH 1  := FALSE;

//----------------------------------------------------------------------------------
// Memory Test. Returns 1 for a failure, 0 for a pass.
// Calls MemTest (memtestSDRAM.xje) and tests CKE and nCS.
//----------------------------------------------------------------------------------
Test()(INT testFail)
//----------------------------------------------------------------------------------

  PRINT("\nTesting ", SIZE_MB, " Mbyte SDRAM [", DEVICE_REF, "]\n");
  testFail := 0;

  PRINT("Initialising...\n");
  Initialise();

  PRINT("Calling MemTest function...\n");
  MemTest()(testFail);

  IF (testFail = 1) THEN
    PRINT("Memory chip ", DEVICE_REF, " FAILED...\n\n");
    Deselect()();
    RETURN;
  END;

  IF WRITEABLE(CKE) THEN
    PRINT("Testing CKE...\n");
    CKETest()(testFail);
    IF testFail = 1 THEN
      PRINT("Memory chip ", DEVICE_REF, " FAILED...\n\n");
      Deselect()();
      RETURN;
    END;
  END;

  IF WRITEABLE(nCS) THEN
    PRINT("Testing NCS...\n");
    NCSTest()(testFail);
    IF testFail = 1 THEN
      PRINT("Memory chip ", DEVICE_REF, " FAILED...\n\n");
      Deselect()();
      RETURN;
    END;
  END;

  PRINT("Memory chip ", DEVICE_REF, " PASSED...\n\n");
  Deselect()();

END;


//----------------------------------------------------------------------------------
// Checks that the CKE pin isn't stuck high
//----------------------------------------------------------------------------------
CKETest()(INT result)
//----------------------------------------------------------------------------------

  INT data WIDTH DATA_BUS_WIDTH;
  result := 0;

  SET CKE := 0;

  WriteCycle(0xAA, 0xBB, 0);
  SET DATA := 0;
  ReadCycle(0xAA)(data);

  IF (DEBUG) THEN
    PRINT("Wrote 0xBB with CKE set low, and read back 0x", HEX(data), "\n");
  END;

  IF (data = 0xBB) THEN
    PRINT("ERROR: CKE stuck high\n");
    result := 1;
  END;

  SET CKE := 1;

END;


//----------------------------------------------------------------------------------
// Checks that the nCS pin isn't stuck low
//----------------------------------------------------------------------------------
NCSTest()(INT result)
//----------------------------------------------------------------------------------

  INT data WIDTH DATA_BUS_WIDTH;

  result := 0;

  // write with NCS high
  SET CLK := 0, COMMAND := 0b1011, ADDR := 0, BANK := 0, DATA := 0xAA;
  SET CLK := 1;

  SET CLK := 0, COMMAND := 0b1111;
  SET CLK := 1;

  SET CLK := 0, COMMAND := 0b1100, DQM := 0, ADDR := 0;
  SET CLK := 1, DATA := I;

  SET CLK := 0, COMMAND := 0b1111;
  SET CLK := 1;

  ReadCycle(0)(data);

  IF (DEBUG) THEN
    PRINT("Wrote 0xAA with NCS high, and read back 0x", HEX(data), "\n");
  END;

  IF (data = 0xAA) THEN
    PRINT("ERROR : NCS stuck low\n");
    result := 1;
  END;

END;




//----------------------------------------------------------------------------------
// Functions required for use of device file with memtestSDRAM.xje
//----------------------------------------------------------------------------------

PrintDQM(INT i)()
  PRINT(PINNUM(DQM[i]));
END;

PrintDQS(INT i)()
END;

PrintAddr(INT i)()
  PRINT(PINNUM(ADDR[i]));
END;

PrintData(INT i)()
  PRINT(PINNUM(DATA[i]));
END;

PrintBank(INT i)()
  PRINT(PINNUM(BANK[i]));
END;


//------------------------------------------------------------------------------------
// Low-level functions...
//------------------------------------------------------------------------------------

Deselect()()
  SET CLK := 0, COMMAND := CMD_DESELECT;
  SET CLK := 1;
END;

WriteNop()()
  SET CLK := 0, COMMAND := CMD_NOP;
  SET CLK := 1;
END;

PrechargeBank(INT bank WIDTH BANK_BUS_WIDTH)()
  SET CLK := 0, COMMAND := CMD_PRE, ADDR[AP_BIT] := 0, BANK := bank;
  SET CLK := 1;
END;

PrechargeAll()()
  SET CLK := 0, COMMAND := CMD_PRE, ADDR[AP_BIT] := 1, BANK := 0;
  SET CLK := 1;
END;

AutoRefresh()()
  SET CLK := 0, COMMAND := CMD_REF;
  SET CLK := 1;
END;

WriteMode(INT mode WIDTH ROW_WIDTH)()
  SET CLK := 0, COMMAND := CMD_MODE, ADDR := mode, BANK := 0;
  SET CLK := 1;
  IF (DEBUG) THEN PRINT("Mode set 0x", HEX(mode), "\n"); END;
END;



//------------------------------------------------------------------------------------
// Initialise SDRAM
//------------------------------------------------------------------------------------

Initialise()()

  INT mode WIDTH ROW_WIDTH;

  SET CLK := 0, CKE := 1, DQM := ~0[DQM_BUS_WIDTH-1..0], COMMAND := CMD_NOP, ADDR := 0, DATA := 0, BANK := 0;

  Deselect();

  // Begin by writing a few NOP cycles.
  WriteNop();
  WriteNop();
  WriteNop();
  WriteNop();
  WriteNop();

  // Then write a PRECHARGE instruction on all banks.
  PrechargeAll();
  WriteNop();
  WriteNop();
  WriteNop();
  WriteNop();

  // Write 2 auto refresh cycles.
  AutoRefresh();
  WriteNop();
  WriteNop();
  AutoRefresh();
  WriteNop();
  WriteNop();

  // Write the MODE register.
  mode       := 0;
  mode[2..0] := BURST_LENGTH;
  mode[3]    := BURST_TYPE;
  mode[6..4] := CAS_LATENCY;
  mode[8..7] := 0b00;
  mode[9]    := 1;
  WriteMode(mode);

  WriteNop();
  WriteNop();

END;



//------------------------------------------------------------------------------------
// WriteCycle
// Address:  BANK[BANK_BUS_WIDTH-1..0] : ROW[ROW_WIDTH-1..0] : COLUMN[COL_WIDTH-1..0]
//------------------------------------------------------------------------------------

WriteCycle(INT address WIDTH ADDR_WIDTH, INT data WIDTH DATA_BUS_WIDTH, INT dqm WIDTH DQM_BUS_WIDTH)()

  INT bank WIDTH BANK_BUS_WIDTH := address[(ADDR_WIDTH-1)..(ADDR_WIDTH-BANK_BUS_WIDTH)];
  INT rowA WIDTH ROW_WIDTH := address[(COL_WIDTH+ROW_WIDTH-1)..(COL_WIDTH)]; // Row address
  INT colA WIDTH COL_WIDTH := address[(COL_WIDTH-1)..0];   // Column address

  IF (COL_WIDTH>AP_BIT) THEN
    colA[(COL_WIDTH)..(AP_BIT+1)] := colA[(COL_WIDTH-1)..AP_BIT]; // create space for the Auto pre charge bit
  END;

  colA[AP_BIT] := 1;

  IF (DEBUG) THEN
    PRINT("Write : address=0x", HEX(address), " [Bank=0x", HEX(bank), " col=0x", HEX(colA), " row=0x", HEX(rowA), "] data=0x", HEX(data), "\n");
  END;

  SET CLK := 0, COMMAND := CMD_ACTIVE, ADDR := rowA, BANK := bank, DATA := data;
  SET CLK := 1;

  SET CLK := 0, COMMAND := CMD_NOP;
  SET CLK := 1;

  SET CLK := 0, COMMAND := CMD_WRITE, DQM := dqm[DQM_BUS_WIDTH-1..0], ADDR := colA;
  SET CLK := 1, DATA := I;

  WriteNop()();
  WriteNop()();
  WriteNop()();

END;

//------------------------------------------------------------------------------------
// ReadCycle
// Address:  BANK[BANK_BUS_WIDTH-1..0] : ROW[ROW_WIDTH-1..0] : COLUMN[COL_WIDTH-1..0]
//------------------------------------------------------------------------------------

ReadCycle(INT address WIDTH ADDR_WIDTH)(INT data WIDTH DATA_BUS_WIDTH)

  INT bank WIDTH BANK_BUS_WIDTH := address[(ADDR_WIDTH-1)..(ADDR_WIDTH-BANK_BUS_WIDTH)];
  INT rowA WIDTH ROW_WIDTH := address[(COL_WIDTH+ROW_WIDTH-1)..(COL_WIDTH)]; // Row address
  INT colA WIDTH COL_WIDTH := address[(COL_WIDTH-1)..0];   // Column address
  INT casloop;

  IF (COL_WIDTH>AP_BIT) THEN
    colA[(COL_WIDTH)..(AP_BIT+1)] := colA[(COL_WIDTH-1)..AP_BIT]; // create space for the Auto pre charge bit
  END;

  colA[AP_BIT] := 1;

  SET CLK := 0, COMMAND := CMD_ACTIVE, ADDR := rowA, BANK := bank, DATA := I, DQM := 0;
  SET CLK := 1;

  SET CLK := 0, COMMAND := CMD_NOP ;
  SET CLK := 1;

  SET CLK := 0, COMMAND := CMD_READ, ADDR := colA;
  SET CLK := 1;

  FOR casloop := 0 FOR CAS_LATENCY - 1
    SET CLK := 0, COMMAND := CMD_NOP;
    SET CLK := 1;
  END;

  SET CLK := 0;
  SET CLK := 1, data := DATA;

  WriteNop()();
  WriteNop()();
  WriteNop()();

  IF (DEBUG) THEN
    PRINT("Read : address=0x", HEX(address), " [Bank=0x", HEX(bank), " col=0x", HEX(colA), " row=0x", HEX(rowA), "] data=0x", HEX(data), "\n");
  END;

END;