/****************************************************************************
    Copyright (C) 1987-2005 by Jeffery P. Hansen

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
****************************************************************************/
#ifndef __thyme_h
#define __thyme_h

/*
  State symbol codes
 */
#define SYM_NUL1	0
#define SYM_ZERO	1
#define SYM_ONE		2
#define SYM_NUL2	3
#define SYM_FLOAT	4
#define SYM_LOW		5
#define SYM_HIGH	6
#define SYM_UNKNOWN	7


/*
   Event classes
*/
#define EV_UNKNOWN	0	/* An unknown event type */
#define EV_NET		1	/* A net changed value */
#define EV_PORT		2	/* A port changed value */
#define EV_GATE		3	/* A gate event occured */
#define EV_CONTROL	4	/* A control event occured */

/*
  Control event types
 */
#define EVC_STOP	0	/* Halt the queue */

/*
   Event queue flags
*/
#define EVF_RUN		0x1	/* Event queue is free running */
#define EVF_POSCLOCK	0x2	/* Wait for a clock posedge transition */
#define EVF_NEGCLOCK	0x4	/* Wait for a clock negedge transition */
#define EVF_HASCLOCK	0x8	/* The circuit contains at least one clock */
#define EVF_PERSRUN	0x10	/* Presistent run mode (run flag will be set when a switch is set) */
#define EVF_NOCMD	0x20	/* Do not process commands */

#define NO_TIME		-1	/* A non-time value */

/*
  Breakpoint opcodes
 */
#define	BPO_EQUAL	0
#define	BPO_NEQ		1

/*
  Get the net affected by an event
 */
#define getEvNet(E)		(((E)->evclass == EV_NET) ? (E)->evnet.net : (E)->evport.port->p_net)

/*
  Test if event E is a change on port number n of g
 */
#define IsChangeOn(E,g,n)	(getEvNet(E) == (g)->g_ports.port[(n)]->p_net)

typedef int simTime;		/* Simulation time */ 

/*
         Logic values
         0  1  x  z  L  H
-------------------------
zero     1  0  1  0  1  0
one      0  1  1  0  0  1
flt      0  0  1  1  1  1
*/
struct sstate {
  int status;
  short		nbits;		/* Number of bits in state */
  short		nalloc;		/* Number of words allocated */
  unsigned	*zero;
  unsigned	*one;
  unsigned	*flt;
};

struct sstate_fl {
  SState		state;	/* Actual state data */
  struct sstate_fl	*next;	/* Next pointer for free list */
};

struct breakpoint {
  int		bp_id;		/* ID # of breakpoint */
  char		*bp_text;	/* Text of breakpoint */
  SNet		*bp_net;	/* Net breakpoint is on */
  SState	*bp_value;	/* Target value */
  int		bp_op;		/* Operation */
};

struct base_sevent {
  int		evclass;	/* Type of event */
  simTime	time;		/* Time of event */
  SEvent	*next;		/* Next event in bucket */
  SState	state;		/* New state of net */
  int		status;
};

struct net_sevent {
  int		evclass;	/* Type of event */
  simTime	time;		/* Time of event */
  SEvent	*next;		/* Next event in bucket */
  SState	state;		/* New state of net */
  int		status;

  SNet		*net;		/* Net which changed */
};

struct port_sevent {
  int		evclass;	/* Type of event */
  simTime	time;		/* Time of event */
  SEvent	*next;		/* Next event in bucket */
  SState	state;		/* New state of net */
  int		status;

  SPort		*port;		/* Net which changed */
};

struct gate_sevent {
  int		evclass;	/* Type of event */
  simTime	time;		/* Time of event */
  SEvent	*next;		/* Next event in bucket */
  SState	state;		/* New state of net */
  int		status;

  SGate		*gate;		/* Gate on which event occurred */
  int		type;		/* Event code for gate */
  void		*gdata;		/* Optional data to send with event */
};

struct ctl_sevent {
  int		evclass;	/* Type of event */
  simTime	time;		/* Time of event */
  SEvent	*next;		/* Next event in bucket */
  SState	state;		/* New state of net */
  int		status;

  int		type;		/* Control code */
  void		*data;		/* Control data */
};

union sevent {
  int			evclass;
  struct base_sevent	evbase;
  struct net_sevent	evnet;
  struct port_sevent	evport;

  struct gate_sevent	evgate;
  struct ctl_sevent	evctl;
};

struct evqueue {
  SModule	*mod;				/* Expanded module being simulated */
  unsigned	flags;				/* Event queue flags */

  int		clockHold;			/* Cycles to wait after clock posedge */
  int		clockCount;			/* Number of clock cycles to step */
  SGate		*triggerClock;			/* Clock to trigger on (null if any clock) */

  int		curStep;			/* Current time step */
  int		numPending;			/* Number of pending events */
  SEvent	*wheel_head[THYMEWHEEL_SIZE];	/* Event queues for each step (for dequeue) */
  SEvent	*wheel_tail[THYMEWHEEL_SIZE];	/* Event queues for each step (for enqueue) */

  SEvent	*wheel_overflow;		/* Overflow events ouside regular time window */

  NHash		bptable;			/* Table of breakpoints */
};

#define EvQueue_pending(Q)	(Q)->numPending
#define EvQueue_curPending(Q)	((Q)->wheel_head[((Q)->curStep & THYMEWHEEL_MASK)] != 0)

void EvQueue_init(EvQueue *Q,SModule *M);
void EvQueue_mainEventLoop(EvQueue *Q);
SEvent *EvQueue_dequeue(EvQueue*);
void EvQueue_process(EvQueue*,SEvent*);
void EvQueue_execute(EvQueue*,char*);

void EvQueue_enqueue(EvQueue*,SEvent*);			/* Generic event enqueue */
void EvQueue_setNet(EvQueue*,SNet*,SState*,int);	/* Enqueue a net value change event */
void EvQueue_setPort(EvQueue*,SPort*,SState*,int);	/* Enqueue a port value change event */
void EvQueue_qGateEv(EvQueue*,SGate*,int,void*,int);	/* Enqueue a gate event */
void EvQueue_control(EvQueue*,int,void*,int);		/* Enqueue a queue control event */
void EvQueue_addBreak(EvQueue*,int,char*);		/* Add a breakpoint */
void EvQueue_delBreak(EvQueue*,int);			/* Delete a breakpoint */
void EvQueue_check(EvQueue*);

SEvent *new_SEvent();
void delete_SEvent(SEvent*,int);

void SState_init(SState *S,int nbits);
void SState_uninit(SState *S);
void SState_reinit(SState *S,int nbits);
void SState_zero(SState *S);
void SState_one(SState *S);
void SState_unknown(SState *S);
void SState_float(SState *S);
void SState_print(SState *S,FILE *f);
void SState_convert(SState *S,char *A);
void SState_not(SState *R,SState *A);
void SState_buf(SState *R,SState *A);
void SState_copy(SState *R,SState *A);
void SState_or(SState *R,SState *A,SState *B,int);
void SState_and(SState *R,SState *A,SState *B,int);
void SState_xor(SState *R,SState *A,SState *B,int);
void SState_copyRange(SState *R,int rl,SState *A,int ah,int al);
void SState_expandExtend(SState *R,int nbits);
int SState_getBitSym(SState*,int);
int SState_convertToInt(SState*,unsigned*);
int SState_convertFromInt(SState*,unsigned);
int SState_isLogic(SState*);
int SState_getstr(SState *S,char *p);
void SState_wire(SState *R,SState *A,SState *B);
void SState_bufif(SState *R,SState *I,SState *E);
void SState_nmos(SState *R,SState *I,SState *G);
void SState_pmos(SState *R,SState *I,SState *G);
int SState_isValue(SState *S);
void SState_shift(SState *R,SState *I,int shift,int in1,int in0,int inZ);
void SState_roll(SState *R,SState *I,int shift);

int SState_eq(SState*,SState*);

SState *alloc_SState();
void free_SState(SState*);

#endif


