/*
 * Jazz library for PamDC: base definitions.
 * Patrice Bertin <Patrice.Bertin@cma.ensmp.fr>
 * CMA-Paris, Ecole des Mines de Paris
 */

package jazz.circuit.pam;

import jazz.circuit.*;

/******************************************************************************
 *
 *                           Extern devices
 *
 *****************************************************************************/

/*
 * Multiple-source bus.
 */

public extern device Bus {
  // number of inputs
  public n: int;

  // data in
  public input in: Net[n];
  // output disable
  public input disable: Net[n];
  // data output
  public output out: Net;

  public pullup(): ();
  public pulldown(): ();
  public weakKeeper(): ();
  public openDrain(): ();

  @ Device.setName("PamDC_Bus");
}

pullup@Bus() = () {
  @ pragma("PamDC_pullup", "%n", out);
}
pulldown@Bus() = () {
  @ pragma("PamDC_pulldown", "%n", out);
}
weakKeeper@Bus() = () {
  @ pragma("PamDC_weakKeeper", "%n", out);
}
openDrain@Bus() = () {
  @ pragma("PamDC_openDrain", "%n", out);
}

/*
 * 16- or 32-bit asynchronous RAM block
 */

public extern device RAM {
  // number of address bits - must be 4 or 5
  public naddr: int;

  // address input
  public input addr: Net[naddr];
  // data input
  public input in: Net;
  // write enable
  public input write: Net;

  // data output
  public output out: Net;

  @ Device.setName("PamDC_RAM");
  assert(naddr == 4 || naddr == 5);
}

/*
 * 16- or 32-bit ROM block
 */

public extern device ROM {
  // number of address bits - must be 4 or 5
  public naddr: int;
  // content
  public init: int;

  // address input
  public input addr: Net[naddr];
  // data output
  public output out: Net;

  @ Device.setName("PamDC_ROM");
  @ Device.setParams(format("init=%d", init));
  assert(naddr == 4 || naddr == 5);
  assert(init >= 0 && init < 2**naddr);
}

/*
 * 16- or 32-bit synchronous RAM block
 */

public extern device RAMS {
  // number of address bits - must be 4 or 5
  public naddr: int;
  // initial value
  public init: int;

  // address input
  public input addr: Net[naddr];
  // data input
  public input in: Net;
  // write enable
  public input write: Net;
  // TEMPORARY: what about clock?

  // data output
  public output out: Net;

  @ Device.setName("PamDC_RAMS");
  @ Device.setParams(format("init=%d", init));
  assert(naddr == 4 || naddr == 5);
  assert(init >= 0 && init < 2**naddr);
}

/*
 * 16-bit dual-ported synchronous RAM block
 */

public extern device RAMD {
  public init: int;            // initial value

  public input a: Net[4];      // write, and 1st port read address
  public input dpra: Net[4];   // 2nd port read address
  public input in: Net;        // data input
  public input write: Net;     // write enable
  // TEMPORARY: what about clock?

  public output spo: Net;      // 1st port output
  public output dpo: Net;      // 2nd port output

  @ Device.setName("PamDC_RAMD");
  @ Device.setParams(format("init=%d", init));
  assert(init >= 0 && init < 2**4);
}

/*
 * Input and output pads.
 */

public extern device InputPad {
  public output o: Net;

  @ Device.setName("PamDC_InputPad");
}

public extern device OutputPad {
  public input i: Net;
  
  @ Device.setName("PamDC_OutputPad");
}

/*
 * Mode pins
 */

public extern device Md0Pad {
  public output o: Net;

  @ Device.setName("PamDC_Md0Pad");
}

public extern device Md1Pad {
  public input i: Net;
  public input t: Net;

  @ Device.setName("PamDC_Md1Pad");
}

public extern device Md2Pad {
  public output o: Net;

  @ Device.setName("PamDC_Md2Pad");
}

/*
 * Readback block.
 */

public extern device Rdbk {
  public input trig: Net;
  public output data: Net;
  public output rip: Net;

  @ Device.setName("PamDC_Rdbk");
}

/******************************************************************************
 *
 *                     Base class for chip-level devices
 *
 *****************************************************************************/

public abstract device Chip {
  public filename: String;

  // Chip type -- mandatory (no default).
  public part(): String;
  public pkg(): String;
  public speedGrade(): int;

  // Default clock period. Default is 0 (meaning no constraint).
  public defaultClockPeriod(): int;

  @ pragma("PamDC_Chip", "%b %s %s %s %d %d",
     filename, part(), pkg(), speedGrade(), defaultClockPeriod());
}

defaultClockPeriod@Chip() = 0;

/******************************************************************************
 *
 *                           Static functions
 *
 *****************************************************************************/

public class PamDC {
  // Assign an IOB to a net
  public static assignIOB(n: Net, pin: int): ();

  // Declare an IOB to be input-only
  public static assignIOBInput(pin: int): ();

  // Absolute placement directive
  public static loc(n: Net, x: int, y: int): ();
  // Relative placement directive
  public static rloc(n: Net, n': Net, x: int, y: int): ();

  // horizontal placement of an internal tri-state bus
  // "n" is the tri-state bus, "pos" is one of UPPER, LOWER, UNPLACED,
  // "row" is desired row, or -2 if none.
  public static busLoc(n: Net, pos: int, row: int): ();
  public static UPPER: int = 0;
  public static LOWER: int = 1;
  public static UNPLACED: int = 2;

  // vertical placement of a tri-state buffer
  // "n" is the tri-state bus, "disable" is the disable input to the buffer
  public static busDisableLoc(n: Net, disable: Net, column: int): ();

  // placement of a global buffer
  public static globalBuffer(n: Net, place: int): ();
  public static ACLK: int = 0;
  public static GCLK: int = 1;
  public static BUFGS: int = 2;
  public static BUFGP: int = 3;
  public static BUFG: int = 4;

  // set the default clock -- TEMPORARY?
  public static setDefaultClock(n: Net): ();
}

PamDC.assignIOB(n, pin) = ()
{
  @ pragma("PamDC_assignIOB", "%n %d", n, pin);
}

PamDC.assignIOBInput(pin) = ()
{
  @ pragma("PamDC_assignIOBInput", "%d", pin);
}

PamDC.loc(n, x, y) = ()
{
  @ pragma("PamDC_loc", "%n %d %d", n, x, y);
}

PamDC.rloc(n, n', x, y) = ()
{
  @ pragma("PamDC_rloc", "%n %n %d %d", n, n', x, y);
}

PamDC.busLoc(n, pos, row) = ()
{
  @ pragma("PamDC_busLoc", "%n %d %d", n, pos, row);
}

PamDC.busDisableLoc(n, disable, column) = ()
{
  @ pragma("PamDC_busDisableLoc", "%n %n %d", n, disable, column);
}

PamDC.globalBuffer(n, place) = ()
{
  @ pragma("PamDC_globalBuffer", "%n %d", n, place);
}

PamDC.setDefaultClock(n) = ()
{
  @ pragma("PamDC_setDefaultClock", "%b %n", n);
}