/* Copyright (c)1994-2000 Begemot Computer Associates. All rights reserved.
 * See the file COPYRIGHT for details of redistribution and use. */
/* $Id: proc.h 502 2002-09-04 13:31:20Z hbb $ */

# include <sys/types.h>
# include <sys/param.h>
# include <sys/socket.h>
# include <sys/time.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <sys/wait.h>
# include <sys/uio.h>
# include <stddef.h>
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
# include <signal.h>
# include <stdarg.h>
# ifdef HAVE_STREAMS
#  include <stropts.h>
# endif
# include <stdlib.h>
# include <string.h>
# include <setjmp.h>
# include <termios.h>
# include <errno.h>
# include <assert.h>
# include <limits.h>
# include <time.h>

# ifdef HAVE_GETOPT_H
#  include <getopt.h>
# endif

# include <begemot.h>
# include "cdefs.h"
# include "pathnames.h"
# include "libutil/util.h"
# include "bits.h"

/*
 * tunable parameters
 */
# define PHYSMEM 	(4*1024*1024)
# define FD_DEVICES	64
# define P11CONF	"p11conf"
# define MAXTIMEOUT	13


/* maximum length of a controller name (including the instance number) */
# define MAXCTRLNAME	50

/* Some systems have qaud_t defined to be a 64-bit structure.
 * So we use our own names instead of doing a lot of configuration
 * work */
typedef long long xquad_t;
typedef unsigned long long u_xquad_t;

typedef void		(*const VPF)(void);


typedef enum mmode mmode_t;
enum mmode {
	M_Word		= 0,	/* word				*/
	M_Low		= 1,	/* low byte			*/
	M_High		= 2,	/* high byte			*/
};

/*
 * This is a opaque type for all of the emulator expect the memory
 * implementation. Therefor we have only a forward declaration in this
 * file.
 */
typedef struct mmg mmg_t;


typedef void	(*PFstore)(u_int a, int space, int mode, u_short v);
typedef void	(*PFstoreb)(u_int a, int space, int mode, u_short v);
typedef u_int	(*PFfetch)(u_int a, int space, int mode);

typedef struct macc {
	PFstore	store;
	PFstoreb storeb;
	PFfetch	fetch;
} macc_t;

/*
 * Device and global configuration Options
 */
typedef struct opt opt_t;
struct opt {
	char	*name;		/* name of the option */
	enum {
		OptString,	/* this is a string option */
		OptInt,		/* this is a integer option */
		OptUInt,	/* this is a unsigned integer option */
		OptFlag,	/* this is a flag */
		OptFunc,	/* call function */
	}	type;
	size_t	off;		/* offset */
};

typedef struct iocmd	iocmd_t;
typedef struct ioops 	ioops_t;
typedef struct ioconf	ioconf_t;
typedef struct iodev	iodev_t;

/*
 * Per-Controller-Class structure
 */
struct ioops {
	void		(*ctrl_create)(iodev_t *, int, char **);
	void		(*dev_create)(iodev_t *, int, char **);
	void		(*ctrl_complete)(iodev_t *);
	void		(*reset)(iodev_t *);
	u_short		(*fetch)(iodev_t *, u_int);
	void		(*store)(iodev_t *, u_int, mmode_t, u_short);
	u_short		(*vector)(iodev_t *);
	void		(*dma)(iodev_t *);
	void		(*async)(iodev_t *, void *);
	void		(*info)(iodev_t *);
	void		(*flush)(iodev_t *);

	iocmd_t		*cmds;
};

/*
 * "Bootstrap" structure.
 */
struct ioconf {
	char	*xname;		/* name ala "kl", "rl", ... */
	ioops_t	*ioops;		/* class specific functions */
	u_int	count;		/* current number of controllers */
	opt_t	*opts;		/* controller options */
};

/*
 * Per-Controller-structure
 */
struct iodev {
	int		reqpri;		/* current request priority */
	iodev_t		*next;		/* next controller on bus */
	void		*data;		/* private controller data */
	ioops_t		*ioops;		/* operations vector */
	ioconf_t	*conf;		/* pointer to configuration info */
	u_int		instance;	/* instance number for this type */
};

/*
 * device command table entry
 */
struct iocmd {
	char		*name;
	char		*usage;
	int		(*func)(iodev_t *, int, char **);
};


/*
 * entry points to non-generic memory part
 */
typedef struct memops	memops_t;
struct memops {
	void	(*reset)(mmg_t *);		/* bus reset		*/
	void	(*mmr0)(mmg_t *);		/* mmr0 written		*/
	void	(*mmr3)(mmg_t *);		/* mmr3 written		*/
	void	(*par)(mmg_t *, int, int, int);	/* par written		*/
	void	(*pdr)(mmg_t *, int, int, int);	/* pdr written		*/
	void	(*ccr)(mmg_t *);		/* ccr written		*/
	void	(*info)(mmg_t *);		/* odt info */
	macc_t	a16, a18, a22;			/* access functions */
	u_short  *(*addrphys)(mmg_t *, u_int);	/* for dma		*/
};

/*
 * pdp float/double format
 * this structure MUST be 4 u_shorts (64 bits) long or some code will break
 */
typedef struct pdp_float pdp_float_t;
# ifdef WORDS_BIGENDIAN
struct pdp_float {
	u_int		s : 1;		/* sign */
	u_int		e : 8;		/* expo offset 0200 */
	u_int		m0 : 7;		/* 7 bits in 1st word */
	u_int		m1 : 16;	/* 1nd word */
	u_int		m2 : 16;	/* 2nd word */
	u_int		m3 : 16;	/* 3nd word */
};
# else
struct pdp_float {
	u_int		m0 : 7;		/* 7 bits in 1st word */
	u_int		e : 8;		/* expo offset 0200 */
	u_int		s : 1;		/* sign */
	u_int		m1 : 16;	/* 1nd word */
	u_int		m2 : 16;	/* 2nd word */
	u_int		m3 : 16;	/* 3nd word */
};
# endif
# define PDP_OFF	0200		/* exponent excess */

/*
 * floating point processor
 */
typedef struct fpregs fpregs_t;
struct fpregs {
	pdp_float_t	ac[6];		/* AC0-6 */
	u_short		st;		/* state */
	u_short		fec;		/* exception code */
	u_short		fea;		/* exception address */
};


/*
 * processor
 */
typedef struct proc proc_t;
struct proc {
	u_short		reg[8];		/* registers for cur. mode	*/
	u_short		ureg[6];	/* R0-R5			*/
	u_short		kreg[6];	/* R0'-R5'			*/
	u_short		sp[4];		/* SP				*/

	u_short		cpuerr;		/* CPU error register		*/
	u_short		pirq;		/* programmed interrupt request	*/
	u_short		ltc;		/* line time clock		*/
	u_short		maint;		/* maintenance			*/
	u_short		ccr;		/* cache control :-)		*/
	int		bevent;		/* if true - timer disabled 	*/

	int		fpd;		/* disable FPP			*/
	fpregs_t	fpp;		/* floating point registers	*/

	/* PSW */
	u_char		c, n, v, z;
	int		t;
	int		pri;
	int		regs;
	int		curmode;	/* mode from psw 		*/
	int		prevmode;	/* previous mode  		*/

	mmg_t		*mmg;		/* memory manager		*/
	memops_t	*memops;	/* operations			*/
	u_short		mmr0;
	u_int		mmr2;		/* trapping pc			*/
	u_int		mmr3;		/* 				*/
	int		mmfrozen;
	u_short		fmmr0, fmmr1, fmmr2;
	int		mmr1reg[2];	/* register part		*/
	int		mmr1chg[2];	/* change part			*/
	macc_t		mop;
	u_short		par[4][2][8];
	u_short		pdr[4][2][8];

	u_int	 	physmem;	/* amount of phys. mem (bytes)	*/
	iodev_t		*iopage[4096];

	int		reqpri;		/* highest pending bus request	*/
	iodev_t		*devices;
	iodev_t		*proc;		/* processor registers */

	u_int		cmd;		/* last ifetch			*/
	int		push;		/* if true last op did stack push */
	u_short		bp;		/* breakpoint 			*/
	int		tinhibit;	/* tbit trap pending		*/
	int		halt;		/* stop processor		*/
	int		stop10;		/* stop in trap 10 */
	int		stop4;		/* stop in trap 4 */
	int		no22;		/* pretend 18 bit */
};


void	dev_command(iodev_t *, int, char **);
int	dev_help(iodev_t *, int, char **);

typedef enum dmadir_t 	dmadir_t;
enum dmadir_t {
	WriteMem,	/* from buffer into memory */
	ReadMem,	/* from memory to buffer */
	CmpMem,		/* compare memory and buffer */
};
u_int	dma(void *buf, u_int bytes, u_int mem, dmadir_t direction, int *);

extern proc_t 	proc;
extern u_short	startloc;
extern int	ill_trace;
extern int	nomon;

/*
 * Global options
 */
typedef struct glob glob_t;
struct glob {
	char	*libpath;
	char	*iodir;
	u_int	clock_rate;
};
extern glob_t	globopts;


char *	print_mmr0(u_short);
char *	print_mmr1(u_short);
char *	print_mmr3(u_short);

extern char	verbose[128];

extern jmp_buf	trap;

void	push(u_short);
u_short	pop(void);
void	switchmode(int, int);
void	interp(void) DEAD_FUNC;
void	Reset(void);
void	Flush(void);
void	catch_io_sigs(void);

/*
 * generic memory interface
 */
u_short iofetch(u_int a);
void 	iostore(u_int a, u_short v);
void 	iostoreb(u_int a, u_short v);
# define mmfetch(A,D,M)		proc.mop.fetch((A),(D),(M))
# define mmstore(A,D,M,V)	proc.mop.store((A),(D),(M),(V))
# define mmstoreb(A,D,M,V)	proc.mop.storeb((A),(D),(M),(V))
# define mfetch(A,D) 		mmfetch((A),(D),proc.curmode)
# define mstore(A,D,V)		mmstore((A),(D),proc.curmode,(V))
# define mstoreb(A,D,V)		mmstoreb((A),(D),proc.curmode,(V))
void	mem_init(void);		/* 1st initialisation	*/


void	Trap(u_short) DEAD_FUNC;
void	Trap10(void) DEAD_FUNC;
void	Trap4(u_short) DEAD_FUNC;
void	YellowTrap(void) DEAD_FUNC;
void 	MemTrap(int, int, int, u_short) DEAD_FUNC;
void	SetupTrap(u_short);
void	proc_pwrfail(int real);
void	pwrfail_exit(void *);

void	mon_fpp(void);
void	store_long(int);
void	store_float(u_short *, int, int);
void 	load_float(u_short *, int, int);
void	load_long(int);

u_int	parse_csr(char *, char *);
u_short	parse_vec(char *, char *);
u_short	parse_irq(char *, char *);

int	register_handler(char *, char *[], iodev_t *, void *, int, pid_t *);
int	register_timer(u_int, void (*)(void *), void *);
void	reset_timer(u_int, int);

void	monitor(void);
void	type_help_file(char *help);
void	request(void);
void	conf_warning(char *, ...);
void	conf_panic(char *, ...) DEAD_FUNC;
char	*ctrlname(iodev_t *, int);
void	device_info(void);
FILE	*lib_fopen(const char *fname, char **fn);
int	lib_open(const char *fname, char **fn);

void	init_timer(void);
void	start_timer(void);
int	stop_timer(void);

void	utrace(void);

# define Max(A,B)	(((A) > (B)) ? (A) : (B))
# define Off(A) ((A) >> 1)
# define IOP(A) (((A) & 017777) >> 1)

/*
 * Host byte ordering dependend stuff. These macros must be used to
 * access memory because the memory is hold in pdp byte order.
 * This is done in order to be able to use memory mapped disk images.
 */
# ifdef WORDS_BIGENDIAN
#  define SETLB(W, V)    ((W) = ((W) & 0377) | ((V) << 8 ))
#  define SETHB(W, V)    ((W) = ((W) & 0177400) | (((V) & 0377) >> 0))
#  define SETW(W,V)      ((W) = (u_short)(((V)<<8) | (((V)>>8)&0xff)))
#  define GETW(V)        ((((V)&0xff)<<8)|(((V)>>8)&0xff))
# else
#  define SETLB(W, V)    ((W) = ((W) & 0177400) | (((V) & 0377) << 0))
#  define SETHB(W, V)    ((W) = ((W) & 0000377) | (((V) & 0377) << 8))
#  define SETW(W,V)      ((W) = (V))
#  define GETW(V)        (V)
# endif

/*
 * These macros are used to set the lower or higher byte of a
 * 16-bit value to lower or higher byte of the argument.
 */
# define SLB(W, V)    ((W) = ((W) & 0177400) | ((V) & 0377))
# define SHB(W, V)    ((W) = ((W) & 0377) | ((V) & 0177400))

# define SETWORD(W,M,V)			\
	switch(M) {			\
	  case M_Low:			\
		SLB((W),(V)); break;	\
	  case M_High:			\
		SHB((W),(V)); break;	\
	  case M_Word:			\
		(W) = (V); break;	\
	}

/*
 * Must be higher, than anything else ...
 */
# define NMIPRI 	10
# define DMAPRI		11
# define IRQ(D, L)	((D)->reqpri = (L), proc.reqpri = Max(proc.reqpri,(L)))
# if 0
# define SETPRI(P)	{ \
	extern u_xquad_t cycle; \
	if(proc.pri != (P)) \
		printf("+++ setpri(%d->%d), reqpri=%d, cyc=%d\n", \
			proc.pri, (P), proc.reqpri, cycle); \
	proc.pri = (P); \
}
# else
#  define SETPRI(P) { proc.pri = (P); }
# endif

# define SUBSTR(SUB,S) (strlen((SUB)) <= strlen((S)) && strncmp((S), (SUB), strlen((SUB))) == 0)
# define xstrdup(S,F)	strcpy(xalloc(strlen((S))+1, (F)), (S))

# ifndef MAP_FILE
#  define MAP_FILE 0
# endif
