// Copyright (c) 2000 by David G. Conroy

// Permission to use, copy, modify, and distribute this software and its
// documentation for any purpose and without fee is hereby granted, provided
// that the above copyright notice appears in all copies and that both the
// above copyright notices and this permission notice appear in supporting
// documentation, and that the name of David G. Conroy not be used in advertising
// or publicity pertaining to distribution of the software without specific,
// written prior permission.  This software is made available "as is", and
// David G. Conroy disclaims all warranties, express or implied, with regard to
// this software, including without limitation all implied warranties of
// merchantability and fitness for a particular purpose, and in no event shall
// David G. Conroy be liable for any special, indirect or consequential damages
// or any damages whatsoever resulting from loss of use, data or profits,
// whether in an action of contract, tort (including negligence) or strict
// liability, arising out of or in connection with the use or performance of
// this software.

#define	POS_NONE	0
#define	POS_GY		1
#define	POS_FX		2
#define	POS_H		3

#define	KIND_IN		0
#define	KIND_OUT	1
#define	KIND_TRI	2

#define	CON_NONE	0
#define	CON_0		1
#define	CON_1		2

#define	NNAME		32
#define	NARG		256

class Link;
class TChip;
class Wire;

// Each cell in the FPGA is represented by
// a Cell object. Dangling off each cell is a list of all of the
// ports attached to the cell, as Link objects.

class Cell {
	friend class TChip;
	friend class Link;
	friend class Wire;
public:
	Cell(char *aType);
	~Cell();
	void AddArg(char *aArg);
	void SetLoc(int aRow, int aCol);
	void SetLoc(int aRow, int aCol, int aFlag);
	void AddLink(Link* aLink);
	void DelLink(Link* aLink);
	void DelAllLink();
	void Check();
	void Write(FILE* file);
	Link* FindLink(char* aName);
	void ExpandGenF();
	void ExpandGenG();
	void ExpandOptG();
	void ExpandGenFG();
	void ExpandOptFG();
	void ExpandForceCI();
	void ExpandForceF1();
	void ExpandExamineCI();
	int IsType(char* aType);
	int IsTypeTail(char* aTypeTail);
	void SetType(char* aType);
	void SetTypeTail(char* aTypeTail);
	int GetLocRow() { return (row); }
	int GetLocCol() { return (col); }
	int GetLocPos() { return (pos); }
private:
	struct Links {
		Links* next;
		Link* link;
	};
	TChip* chip;
	char name[NNAME];
	char type[NNAME];
	char arg[NARG];
	int row;
	int col;
	int pos;
	Links* links;
	Cell (Cell&);
	Cell& operator = (Cell&);
};

// Each wire in the FPGA is represented by
// a Wire object. Dangling off each Wire is a list of all the
// ports attached to the cell, as Link objects.

class Wire {
	friend class TChip;
	friend class Link;
	friend class Cell;
public:
	Wire();
	~Wire();
	void AddArg(char* aArg);
	void SetLoc(int aRow, int aCol);
	void SetLoc(int aRow, int aCol, int aFlag);
	void SetName(char* aName);
	void SetName(char* aName, int aIndex);
	void SetCon(int aCon);
	void SetPin(int aPin);
	void SetClk(int aTCyc);
	void SetPadToClk(Wire* aClk, int aTS, int aTH);
	void SetClkToPad(Wire* aClk, int aTMin, int aTMax);
	void SetPadToPad(Wire* aPad, int aTMin, int aTMax);
	void AddLink(Link* aLink);
	void DelLink(Link* aLink);
	void DelAllLink();
	void Check();
	void Write(FILE* file);
	void WriteName(FILE* file);
	void MoveLinks(Wire* aWire);
	Link* FindLink(char* aName);
	Link* FindSourceLink();
	int IsCon0() {
		return (con == CON_0);
	}
	int IsCon1() {
		return (con == CON_1);
	}
	int Has0Links() {
		return (links == 0);
	}
	int Has2Links() {
		return (links!=0 && links->next!=0 && links->next->next==0);
	}
private:
	struct Links {
		Links* next;
		Link* link;
	};
	TChip* chip;
	char name[NNAME];
	char arg[NARG];
	int con;
	int pin;
	Links* links;
	Wire (Wire&);
	Wire& operator = (Wire&);
};

// A Link object represents a named port on
// a cell, along with its type (I, O, T) and the associated Wire.
// You can find all of the Links attached to a Cell by
// tracing a list which begins at the Cell, and you can find all the Links
// attached to a Wire by tracing a list which begins at the Wire.

class Link {
	friend class TChip;
	friend class Wire;
public:
	Link(Wire* aWire, Cell* aCell, int aKind, char* aName);
	~Link();
	Cell* GetCell() { return (cell); }
	Wire* GetWire() { return (wire); }
	void Write(FILE* file);
	int IsIN()  { return (kind ==  KIND_IN); }
	int IsOUT() { return (kind == KIND_OUT); }
	int IsTRI() { return (kind == KIND_TRI); }
	int IsName(char* aName);
	void SetName(char* aName);
private:
	Cell* cell;
	Wire* wire;
	int kind;
	char name[NNAME];
	Link(Link&);
	Link& operator = (Link&);
};

// A TLink binds together a reference to a
// cell, a port name on a cell, and the kind (I, O, T)
// of the port. The functions which add cells to the design
// return filled in TLinks. Client supplied functions which serve
// the same role return TLinks as well.

class TLink {
public:
	TLink(Cell* aCell, int aKind, char* aName);
	~TLink() { }
	Cell* cell;
	int kind;
	char name[NNAME];
private:
	TLink(TLink&);
	TLink& operator = (TLink&);
};

// A TWire is how a client references a Wire.
// It's really just a pointer to an Wire, but there is some
// magic to attach names to Wires, and some overloaded
// operators to make equation writing easy.

class TWire {
public:
	TWire();
	TWire(char* aName);
	TWire(int aPin);
	TWire(char* aName, int aPin);
	TWire(TWire& aTWire);
	TWire(TLink aTLink);
	TWire(Wire* aWire);
	TWire& operator = (TWire aTWire);
	TWire& operator = (TLink aTLink);
	Wire& operator  * () { return (*wire); }
	Wire* operator -> () { return ( wire); }
	operator Wire* ()    { return ( wire); }
private:
	Wire* wire;
};

// TWireVec is like TWire, but is used
// for vectors which arbitrary (little endian) max and min
// subscripts, and array bound checking.
// You can't do much with a TWireVec; you can declare it, and
// you can subscript into it.

class TWireVec {
public:
	TWireVec(int aMaxIndex, int aMinIndex);
	TWireVec(char* aName, int aMaxIndex, int aMinIndex);
	TWireVec(int aMaxIndex, int aMinIndex, int aPinVec[]);
	TWireVec(char* aName, int aMaxIndex, int aMinIndex, int aPinVec[]);
	~TWireVec();
	TWire& operator [] (int aIndex);
private:
	int maxIndex, minIndex;
	TWire* wireVec;
private:
	// block
	TWireVec();
	TWireVec(TWireVec& aTWireVec);
	TWireVec& operator = (TWireVec& aTWireVec);
};

// A TChip is the base for all the
// data associated with the chip. Clients will subclass
// TChip, and put all the code which generates
// the logic of the new chip in the constructor of that subclass.
// Local signals used to be members of this class,
// but now they are just automatic variables in the constructor,
// which seems to work out a little better.

class TChip {
public:
	static TChip* thisChip;
	TChip(char* aName, char* aType);
	~TChip();
	void Trans();
	int GenID() {
		return (++idGen);
	}
	void AddCell(Cell* aCell);
	void DelCell(Cell* aCell);
	void AddWire(Wire* aWire);
	void DelWire(Wire* aWire);
	void Check();
	void Write(FILE* file);
protected:
	// constants
	static TWire Con(long aVal, int aBitIndex = 0);
	// gates, and other cells
	static TLink And(TWire i0, TWire i1);
	static TLink Or(TWire i0, TWire i1);
	static TLink Xor(TWire i0, TWire i1);
	static TLink Inv(TWire i0);
	static TLink Buf(TWire i0);
	static TLink TBuf(TWire i, TWire t);
	static TLink Reg(TWire d, TWire c);
	static TLink Reg1(TWire d, TWire c);
	static TLink Reg0(TWire d, TWire c);
	static TLink RegEn(TWire d, TWire ec, TWire c);	
	static TLink RegEn1(TWire d, TWire ec, TWire c);	
	static TLink RegEn0(TWire d, TWire ec, TWire c);
	static TLink RegRes(TWire d, TWire res, TWire c);
	static TLink RegRes0(TWire d, TWire res, TWire c);
	static TLink RegPre(TWire d, TWire pre, TWire c);
	static TLink RegPre1(TWire d, TWire pre, TWire c);
	static TLink RegResEn(TWire d, TWire res, TWire en, TWire c);
	static TLink RegResEn0(TWire d, TWire res, TWire en, TWire c);
	static TLink RegPreEn(TWire d, TWire pre, TWire en, TWire c);
	static TLink RegPreEn1(TWire d, TWire pre, TWire en, TWire c);
	static TLink BufGP(TWire i);
	static TLink BufGS(TWire i);
	static TLink IPinBuf(TWire d);
	static TLink OPinBuf(TWire d);
	static TLink TPinBuf(TWire d, TWire oe_n);
	static TLink Inc(TWire a, TWire co, TWire ci);
	static TLink Dec(TWire a, TWire co, TWire ci);
	static TLink IncDec(TWire a, TWire co, TWire ci, TWire add);
	static TLink Add(TWire a, TWire b, TWire co, TWire ci);
	static TLink Sub(TWire a, TWire b, TWire co, TWire ci);
	static TLink AddSub(TWire a, TWire b, TWire co, TWire ci, TWire add);
	static void PullUp(TWire a);
	static void DoublePullUp(TWire a);
	static void PullDown(TWire a);
	// syntactic sugar; makes equations look like equations
	friend TLink operator & (TWire a0, TWire a1) { return (And(a0, a1)); }
	friend TLink operator | (TWire a0, TWire a1) { return ( Or(a0, a1)); }
	friend TLink operator ^ (TWire a0, TWire a1) { return (Xor(a0, a1)); }
	friend TLink operator ~ (TWire a0) { return (Inv(a0)); }
private:
	struct Cells {
		Cells* next;
		Cell* cell;
	};
	struct Wires {
		Wires* next;
		Wire* wire;
	};
	char name[NNAME];
	char type[NNAME];
	int idGen;
	Cells* cells;
	Wires* wires;
	TChip (TChip&);
	TChip& operator = (TChip&);
private:
	void DelBufs();
	void MapFGCells();
	void MakeFGCell(Cell* cell1, Cell* cell2);
	void MapFAndGCells();
	void DelCIPins();
	void FixCOPins();
	void FixCIPins();
	void ExpandCells();
};
