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

package jazz.circuit.pam;

import jazz.circuit.*;
import jazz.circuit.pam.PamDC.*;

/******************************************************************************
 *
 *                       PCI-Pamette standard library
 *
 *****************************************************************************/

/*
 * Generic Pamette LCA template.
 */

public device UsrLCA extends Chip {
  // Standard readback module (mandatory).
  public static stdReadback(): ();

  // Standard clock inputs.
  public static getClkUsr(): Net;
  public static getClkSys(): Net;

  // Utility functions to configure and place I/O pins
  public static inputPin(pin: int): Net;
  public static outputPin(net: Net, pin: int): ();
  public static ioPin(net: Net, disable: Net, pin: int): Net;

  // Plug in the standard readback macro
  @ stdReadback();
}

// Default chip specification for Pamette LCAs
part@UsrLCA() = "XC4000E";
pkg@UsrLCA() = "PQ208";
speedGrade@UsrLCA() = 3;

/*
 * Subclassable templates for the 4 individual LCAs.
 */

public device UsrLCA0 extends UsrLCA {
  // Pinout definition
  public static pads: UsrLCA0Pads = new UsrLCA0Pads();
}

public device UsrLCA1 extends UsrLCA {
  // Pinout definition
  public static pads: UsrLCA1Pads = new UsrLCA1Pads();
}

public device UsrLCA2 extends UsrLCA {
  // Pinout definition
  public static pads: UsrLCA2Pads = new UsrLCA2Pads();
}

public device UsrLCA3 extends UsrLCA {
  // Pinout definition
  public static pads: UsrLCA3Pads = new UsrLCA3Pads();
}

/*
 * Asynchronous PCI interface.
 * Usable in LCA0 and LCA1.
 */
public device AsyncPCI {
  public input toPCI: Net[16];
  public output fromPCI: Net[16];

  // Implementation
  for (i < 16) {
    fromPCI[i] = UsrLCA.inputPin(UsrLCA0Pads.ebus[i]);
    @ UsrLCA.outputPin(toPCI[i], UsrLCA0Pads.ebus[i + 16]);
  }
}

/*
 * SRAM bank interface.
 * Usable in LCA0 and LCA1.
 */
public device SRamBank {
  public input addr: Net[15];
  public input wrData: Net[16];
  public input _bank: Net[2];
  public input _write: Net[2];
  public input lcaDisable: Net;
  public input ramDisable: Net;

  public output rdData: Net[16]; 

  // Implementation
  for (i < 15) {
    @ UsrLCA.outputPin(addr[i], SRamPads.addr[i]);
  }
  for (i < 16) {
    rdData[i] = UsrLCA.ioPin(wrData[i], lcaDisable, SRamPads.data[i]);
  }
  for (i < 2) {
     @ UsrLCA.outputPin(_write[i], SRamPads._write[i]);
     @ UsrLCA.outputPin(_bank[i], SRamPads._bank[i]);
  }
  @ UsrLCA.outputPin(ramDisable, SRamPads._oe);
}

/******************************************************************************
 *
 *                       Implementation
 *
 *****************************************************************************/

UsrLCA.stdReadback() = ()
{
  md0 = new Md0Pad().o;
  rdbk_data = new Rdbk(trig = md0).data;
  @ new Md1Pad(i = rdbk_data, t = Net.constant(0));
}

UsrLCA.getClkUsr() = clk
{
  clkin = inputPin(UsrLcaPads.clkusr);
  clk = +clkin;
  @ globalBuffer(clk, BUFG);
}

UsrLCA.getClkSys() = clk
{
  clkin = inputPin(UsrLcaPads.clksys);
  clk = +clkin;
  @ globalBuffer(clk, BUFG);
}

UsrLCA.inputPin(pin) = net
{
  net = new InputPad().o;
  @ assignIOB(net, pin);
}

UsrLCA.outputPin(net, pin) = ()
{
  @ new OutputPad(i = net);
  @ assignIOB(net, pin);
}

UsrLCA.ioPin(o, disable, pin) = i
{
  i = new Bus(n = 1, in = [o], disable = [disable]).out;
  @ assignIOB(i, pin);
}