//------------------------------------------------------
// Nat. Semi. PC87364 SuperIO: XJEase device file
// PC87364_SUPERIO.xje Revision: 1.10
// (c)2004-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.
//------------------------------------------------------

DEVICE NAME := "National Semiconductor PC87364 SuperIO"

  PINS
    // LPC INterface
    LAD     := 18, 17, 16, 15;
    LFRAMEn := 14;
    LRESETn := 10;
    LCLK    := 11;
    LDRQn   := 13;
    SERIRQ  := 12;
    LSMn    := 21;
  END;

  // Device Disable
  DISABLE DEVICE

  END;

  TEST COVERAGE
    LAD     := SHORTS OPEN HI LO;
    LFRAMEn := OPEN HI LO;
    LRESETn := OPEN HI LO;
    LCLK    := OPEN HI LO;
  END;
END;

//------------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------------

// LPC Interface definitions

CONST INT START_START    WIDTH 4 := 0b0000;
CONST INT START_GRANT0   WIDTH 4 := 0b0001;
CONST INT START_GRANT1   WIDTH 4 := 0b0010;
CONST INT START_FREAD    WIDTH 4 := 0b1101;
CONST INT START_FWRITE   WIDTH 4 := 0b1110;
CONST INT START_STOP     WIDTH 4 := 0b1111;

CONST INT TYPE_IOREAD    WIDTH 4 := 0b0000;
CONST INT TYPE_IOWRITE   WIDTH 4 := 0b0010;
CONST INT TYPE_MEMREAD   WIDTH 4 := 0b0100;
CONST INT TYPE_MEMWRITE  WIDTH 4 := 0b0110;
CONST INT TYPE_DMAREAD   WIDTH 4 := 0b1000;
CONST INT TYPE_DMAWRITE  WIDTH 4 := 0b1010;

CONST INT SIZE_8         WIDTH 4 := 0b0000;
CONST INT SIZE_16        WIDTH 4 := 0b0001;
CONST INT SIZE_32        WIDTH 4 := 0b0011;

CONST INT FIRM_MSIZE_1   WIDTH 4 := 0b0000;
CONST INT FIRM_MSIZE_2   WIDTH 4 := 0b0001;
CONST INT FIRM_MSIZE_4   WIDTH 4 := 0b0010;
CONST INT FIRM_MSIZE_16  WIDTH 4 := 0b0100;
CONST INT FIRM_MSIZE_128 WIDTH 4 := 0b0111;

CONST INT SYNC_READY     WIDTH 4 := 0b0000;
CONST INT SYNC_SHORTWAIT WIDTH 4 := 0b0101;
CONST INT SYNC_LONGWAIT  WIDTH 4 := 0b0110;
CONST INT SYNC_MORE      WIDTH 4 := 0b1001;
CONST INT SYNC_ERROR     WIDTH 4 := 0b1010;

CONST INT TAR_FIRST      WIDTH 4 := 0b1111;
CONST INT TAR_SECOND     WIDTH 4 := 0b1111;

CONST INT ADDRESS_LENGTH_IO  := 16;
CONST INT ADDRESS_LENGTH_MEM := 32;

// SuperIO index/data register addresses

CONST INT REG_ADDR_INDEX0  WIDTH 16 := 0x002E;
CONST INT REG_ADDR_DATA0   WIDTH 16 := 0x002F;
CONST INT REG_ADDR_INDEX1  WIDTH 16 := 0x004E;
CONST INT REG_ADDR_DATA1   WIDTH 16 := 0x004F;

// SuperIO configuration registers

CONST INT REG_INDEX_SID    WIDTH 8 := 0x20;
CONST INT REG_INDEX_SIOCF1 WIDTH 8 := 0x21;
CONST INT REG_INDEX_SIOCF2 WIDTH 8 := 0x22;
CONST INT REG_INDEX_SIOCF3 WIDTH 8 := 0x23;
CONST INT REG_INDEX_SIOCF4 WIDTH 8 := 0x24;
CONST INT REG_INDEX_SIOCF5 WIDTH 8 := 0x25;
CONST INT REG_INDEX_SIOCF6 WIDTH 8 := 0x26;
CONST INT REG_INDEX_SRID   WIDTH 8 := 0x27;
CONST INT REG_INDEX_SIOCF8 WIDTH 8 := 0x28;
CONST INT REG_INDEX_SIOCFA WIDTH 8 := 0x2A;
CONST INT REG_INDEX_SIOCFB WIDTH 8 := 0x2B;
CONST INT REG_INDEX_SIOCFC WIDTH 8 := 0x2C;
CONST INT REG_INDEX_SIOCFD WIDTH 8 := 0x2D;

// SuperIO Logical Device Numbers

CONST INT LDN_FDC   WIDTH 8 := 0x00; // Floppy disc controller
CONST INT LDN_PP    WIDTH 8 := 0x01; // Parallel port
CONST INT LDN_SP2   WIDTH 8 := 0x02; // Serial port 2
CONST INT LDN_SP1   WIDTH 8 := 0x03; // SErial port 1
CONST INT LDN_SWC   WIDTH 8 := 0x04; // System wake-up controller
CONST INT LDN_MOUSE WIDTH 8 := 0x05; // Mouse
CONST INT LDN_KBD   WIDTH 8 := 0x06; // Keyboard
CONST INT LDN_GPIO  WIDTH 8 := 0x07; // Gen purpose IO
CONST INT LDN_ACB   WIDTH 8 := 0x08; // Auxilliary control bus
CONST INT LDN_FSCM  WIDTH 8 := 0x09; // Fan speed control & monitor
CONST INT LDN_WDT   WIDTH 8 := 0x0a; // Watchdog Timer

CONST INT DEVICE_ID WIDTH 8 := 0xe4;

//----------------------------------------------------------------------
Test()(INT result)
//----------------------------------------------------------------------

  INT id WIDTH 8;

  PRINT("\tTesting SuperIO controller ", DEVICE_REF, "\n");
  IOWrite(REG_ADDR_INDEX0, REG_INDEX_SID)();
  IORead(REG_ADDR_DATA0)(id);
  PRINT("\tID(0) = 0x", HEX(id), "\n");

  IOWrite(REG_ADDR_INDEX1, REG_INDEX_SID)();
  IORead(REG_ADDR_DATA1)(id);
  PRINT("\tID(1) = 0x", HEX(id), "\n");

END;

//----------------------------------------------------------------------
Initialise()()
//----------------------------------------------------------------------

  SET LRESETn := 0, LFRAMEn := 1, LCLK := 0, LAD := I;
  SET LCLK := 1;

  SET LCLK := 0;
  SET LCLK := 1;

  SET LCLK := 0, LRESETn := 1;
  SET LCLK := 1;

  SET LCLK := 0;
  SET LCLK := 1;

END;

//----------------------------------------------------------------------
IOWrite(INT addr WIDTH 16, INT data WIDTH 8)()
//----------------------------------------------------------------------

  StartTransfer(TYPE_IOWRITE)();
  SendAddress(ADDRESS_LENGTH_IO, addr)();

  SET LCLK := 0, LAD := data[3..0];    // write 8-bit Data
  SET LCLK := 1;

  SET LCLK := 0, LAD := data[7..4];
  SET LCLK := 1;

  HostTar()();
  GetSync()();
  PeripheralTar()();

END;

//----------------------------------------------------------------------
IORead(INT addr WIDTH 16)(INT data WIDTH 8)
//----------------------------------------------------------------------

  StartTransfer(TYPE_IOREAD)();
  SendAddress(ADDRESS_LENGTH_IO, addr)();
  HostTar()();
  GetSync()();

  SET LCLK := 0;                       // read 8-bit Data
  SET LCLK := 1, data[3..0] := LAD;

  SET LCLK := 0;
  SET LCLK := 1, data[7..4] := LAD;

  PeripheralTar()();

END;

//----------------------------------------------------------------------
StartTransfer(INT type WIDTH 4)()
//----------------------------------------------------------------------
  SET LCLK := 0, LAD := START_START, LFRAMEn := 0;   // Start
  SET LCLK := 1;

  SET LCLK := 0, LAD := type, LFRAMEn := 1;;  // Type
  SET LCLK := 1;

END;

//----------------------------------------------------------------------
SendAddress(INT bits, INT addr WIDTH 16)()
//----------------------------------------------------------------------

  IF (bits = ADDRESS_LENGTH_MEM) THEN
    SET LCLK := 0, LAD := addr[31..28];  // 32-bit address
    SET LCLK := 1;

    SET LCLK := 0, LAD := addr[27..24];
    SET LCLK := 1;

    SET LCLK := 0, LAD := addr[23..20];
    SET LCLK := 1;

    SET LCLK := 0, LAD := addr[19..16];
    SET LCLK := 1;
  ELSIF (bits != ADDRESS_LENGTH_IO) THEN
    PRINT("Invalid address bits specified.\n");
    EXIT;
  END;

  SET LCLK := 0, LAD := addr[15..12];  // 16-bit address
  SET LCLK := 1;

  SET LCLK := 0, LAD := addr[11..8];
  SET LCLK := 1;

  SET LCLK := 0, LAD := addr[7..4];
  SET LCLK := 1;

  SET LCLK := 0, LAD := addr[3..0];
  SET LCLK := 1;

END;

//----------------------------------------------------------------------
// Get a sync response from the peripheral
GetSync()()
//----------------------------------------------------------------------
  INT sync WIDTH 4;
  INT timeout := 0;
  CONST INT MAX_TIMEOUT := 8;

  DO                                   // Wait for SYNC_READY
    SET LCLK := 0;
    SET LCLK := 1, sync := LAD;
    IF (sync = SYNC_ERROR) THEN
      PRINT("SYNC ERROR\n");
      EXIT;
    END;
    timeout := timeout + 1;
  WHILE ((sync != SYNC_READY) && (timeout < MAX_TIMEOUT)); END;

  IF (sync != SYNC_READY) THEN
    PRINT("Timeout waiting for SYNC reply from peripheral.\n");
    EXIT;
  END;

END;

//----------------------------------------------------------------------
HostTar()()
//----------------------------------------------------------------------
  SET LCLK := 0, LAD := 0b1111;        // TAR from host
  SET LCLK := 1;

  SET LCLK := 0, LAD := I;
  SET LCLK := 1;
END;

//----------------------------------------------------------------------
PeripheralTar()()
//----------------------------------------------------------------------
  INT tar WIDTH 4;

  SET LCLK := 0;                       // TAR1 from peripheral
  SET LCLK := 1, tar := LAD;
  IF (tar != TAR_FIRST) THEN
    PRINT("Invalid TAR from peripheral.\n");
    EXIT;
  END;

  SET LCLK := 0;                       // TAR2 from peripheral
  SET LCLK := 1, tar := LAD;
  IF (tar != TAR_SECOND) THEN
    PRINT("Invalid TAR from peripheral.\n");
    EXIT;
  END;
END;