/*
	%W%	(%G% %U%)
*/
#ifdef VERS7
#include <sys/unistar.h>
#endif
#ifdef SYSV
#include <sys/config.h>
#endif
#include "standalone.h"

#ifdef mc68012
#define CLOCKADDR	((CLOCK *)(0xff080000))
#else mc68012
#define CLOCKADDR	((CLOCK *)(0x800000))
#endif mc68012

#define CLK_16BIT	0xFFEF	/* Command to select 16-bit mode */
#define CLK_SEQ		0xFFE0	/* Command to enable pointer sequencing */
#define CLK_NSEQ	0xFFE8	/* Command to disable pointer sequencing */
#define CLK_LMODE	0xFF00	/* Command to load the mode register */
#define CLK_LLOAD	0xFF08	/* Command to load the load register */
#define CLK_LHOLD	0xFF10	/* Command to load the hold register */
#define CLK_MODE	0x0B22	/* F1 + Operating mode D */
#define CLK_100		40000	/* 100 HZ interrupt frequency */
#define CLK_200		20000	/* 200 HZ interrupt frequency */
#define CLK_GO		0xFF20	/* Command to arm counter 2 */
#define CLK_LGO		0xFF60	/* Command to load and arm a counter */
#define CLK_SSTOP	0xFF80	/* Command to disarm and save a counter */
#define CLK_SAVE	0xFFA0	/* Command to save a counter */
#define CLK_STOP	0xFFC0	/* Command to disarm a counter */
#define CLK_REFR	0xFFE2	/* Command to re-enable clock */
#define CLK_RESET	0xFFFF	/* Command to master-reset the clock */
#define CLKTIMER	2	/* Timer 2 */

#define CLK_9600_8MHz	13
#define CLK_9600_10MHz	8

#define	CLK_600		208

typedef	struct
	{
	short	clk_data;	/* data register */
	short	clk_cmd;	/* command register */
	}	CLOCK;



#ifdef mc68012
#define	UARTADDR	((UART *)0xfc000040)
#else mc68012
/* The graphics system uses the second UART, channel 0
 * as it's console.
 */
#ifdef GRAPHICS
#define	UARTADDR	((UART *)0x500000)
#else GRAPHICS
#define	UARTADDR	((UART *)0x600000)
#endif GRAPHICS
#endif mc68012

#define SUN0TIMER	4	/* Sun I/O port 0 */
#define SUN1TIMER	5	/* Sun I/O port 1 */
#define XRDY		04	/* transmitter is ready */
#define DRDY		01	/* data is available */

typedef	struct
	{
	char	dbuf;
	char	idum1;
	char	csr;
	char	idum2;
	}	UART;

int	countval;		/* Timeout value for one-second countdown */

#ifdef PANEL
extern int keypos;		/* Current U300 control panel key position */
extern int button;		/* Control panel button press */
extern int noconsole;
#endif PANEL

putchar(c)
	register 	c;
	{
	register 	timo;
	register UART  *uartptr;

#ifdef PANEL
	if (noconsole)
		return;
#endif PANEL
	initchar();
	uartptr = UARTADDR;
	if(c == '\n')
		putchar('\r');
	timo = 200000;
	/*
	 * Wait for console to become ready in some
	 * reasonable time, otherwise wash hands
	 */
	while ((uartptr->csr & XRDY) == 0)
		if (--timo <= 0)
			break;
	if (c == 0) 
		return;
	uartptr->dbuf = c & 0x7F;
	if (c == '\n')
		for (timo = 25000;  --timo >= 0;  )
			;
	}

getchar(timeout)
register int timeout;
{
    register int c, i;
    register UART *uartptr;

    initchar();
    uartptr = UARTADDR;
    while ((uartptr->csr & DRDY) == 0)
    {
	timeout--;
	if (timeout == 0)
	{
#ifdef PANEL
	    button = 0;
	    c = cpdcheck();	/* Check front panel. */
	    if ((c == KEY_ON) || (c == KEY_MAINT))
		keypos = c;
	    else if ((c == BUT_EXEC) || (c == BUT_SELECT)
		|| (c == BUT_PF0) || (c == BUT_PF1))
		button = c;
#endif PANEL
	    return(-2);
	}
    }
    i = uartptr->dbuf & 0177;
    if (i == '\r')
	i = '\n';
#ifdef PANEL
    button = 0;
    c = cpdcheck();		/* Check front panel. */
    if ((c == KEY_ON) || (c == KEY_MAINT))
	keypos = c;
    else if ((c == BUT_EXEC) || (c == BUT_SELECT)
	|| (c == BUT_PF0) || (c == BUT_PF1))
	button = c;
#endif PANEL
    return (i);
}


initchar()
	{
	static   int	suninit;
	int clock_data;
#ifdef CD68K
	register int clkcount;
	register int	waitabit;	/* Dummy for delaying 9513 ref's */
#endif
	register UART  *uartptr;
	register CLOCK *clockptr;

	if (suninit)
		return;
	suninit = 1;
	uartptr  = UARTADDR;
	clockptr = CLOCKADDR;
#ifdef PM68K
	/* old CPU board, only runs at 8 MHz */
	clock_data = CLK_9600_8MHz;
	countval = 156250;
#endif
#ifdef CD68K
/*
	Measure the new CPU's clock speed.  10 MHz is available only on
	CD68K boards with 68010's.
*/
	clockptr->clk_cmd = CLK_RESET;
	waitabit = 0;
	clockptr->clk_cmd = CLK_16BIT;
	waitabit = 0;
	clockptr->clk_cmd = CLK_SEQ;
	waitabit = 0;
	clockptr->clk_cmd = CLK_LMODE + SUN0TIMER;
	waitabit = 0;
	clockptr->clk_data = CLK_MODE;		/* set mode */
	waitabit = 0;
	clockptr->clk_data = 30000;	/* set load reg */
	waitabit = 0;
	clockptr->clk_cmd = CLK_LGO + 0x08; /* enable clock */
/*
	The following delay loop generates this code (execution times for
	the MC68010 are given in the comment field):

		movql	#100,d7		 4 clock cycles
	loop:	subql	#1,d7		 8 clock cycles
		bne	loop		10 clock cycles if taken, 6 if not

	The loop thus takes 18 CPU clock cycles per pass.  At 8 MHz, the
	CPU clock is being divided by 2 to get the timer clock at 4 MHz.  At
	10 MHz, the CPU clock is divided by 4 to get 2.5 MHz.  Thus, at 8 MHz,
	the timer ticks 9 counts per loop pass, while at 10 MHz it ticks
	4.5 counts per pass.  If we count for 100 passes through the loop,
	the timer should decrease by 900 at 8 MHz and 450 at 10 MHz.  The
	loop entry and exit overhead will cause this count to be off by a
	maximum of about 20 more counts.  Thus, when we stop the clock,
	we will have counts of 30000-920 at 8 MHz and 30000-470 at 10 MHz.
	We will arbitrarily draw the line at 30000-700.  (The MC68000 will
	produce an even lower count due to slower instructions;  this is
	OK because it is only supported at 8MHz.)
*/
	for (clkcount = 100; --clkcount; )
		;
	clockptr->clk_cmd = CLK_SSTOP + 0x08; /* Halt clock */
	waitabit = 0;
	clockptr->clk_cmd = SUN0TIMER + CLK_LHOLD;
	waitabit = 0;
	if (clockptr->clk_data > 30000-700) /* 10MHz board? */
		{
		clock_data = CLK_9600_10MHz;
		countval = 204080;
		}
	else
		{
		clock_data = CLK_9600_8MHz;
		countval = 156250;
		}
#endif
	uartptr->csr = 0x18; uartptr->csr = 0x18;	/* UART reset */
	uartptr->csr = 2; uartptr->csr = 0x00;
	uartptr->csr = 4; uartptr->csr = 0x44;
	uartptr->csr = 3; uartptr->csr = 0xE1;
	uartptr->csr = 5; uartptr->csr = 0xEA;
	uartptr->csr = 1; uartptr->csr = 0x00;
	clockptr->clk_cmd  = CLK_LMODE+SUN0TIMER;	/* load-mode */
	clockptr->clk_data = CLK_MODE;			/* set mode */
	clockptr->clk_data = clock_data;		/* set ld reg */
	clockptr->clk_cmd  = CLK_GO+0x08;		/* enable clk */
	}

puts(string)
	register char  *string;
	{
	while (*string)
	    {
	    putchar(*string++);
	    }
	}

printn(number,base,minimum)
	register unsigned int  number;
	register short         base;
	register short         minimum;
	{
	char	      buffer[16];
	register int  i,j;
	static   char table[17] = "0123456789abcdef";

	for (i = 0;  i < sizeof(buffer) - 1;  i++)
	    {
	    buffer[i] = '0';
	    }
	buffer[i--] = 0;
	while (number)
	    {
	    j = number % base;
	    buffer[i--] = table[j];
	    number /= base;
	    }
	j = sizeof(buffer) - i - 2;
	i = j < minimum ? minimum : j;
	puts(&buffer[sizeof(buffer) - 1 - i]);
	}

printf(string,arg)
	register char  *string;
	int             arg;
	{
	register char  *argptr;
	register int    width;

	argptr = (char *)&arg;
	while (*string)
	    {
	    if (*string == '%')
		{
		string++;
		width = 0;
		while ('0' <= *string  &&  *string <= '9')
		    {
		    width *= 10;
		    width += *string - '0';
		    string++;
		    }
		if (width == 0)
		    {
		    width = 1;
		    }
		switch(*string++)
		    {
		    case 'd':
		    case 'D':
			printn(*(unsigned int *)argptr,10,width);
			argptr += 4;
			break;
		    case 'o':
		    case 'O':
			printn(*(unsigned int *)argptr,8,width);
			argptr += 4;
			break;
		    case 's':
			puts(*(unsigned int *)argptr);
			argptr += 4;
			break;
		    case 'x':
		    case 'X':
			printn(*(unsigned int *)argptr,16,width);
			argptr += 4;
			break;
		    default:
			break;
		    }
		}
	    else
		{
		putchar(*string++);
		}
	    }
	}

getlin(buffer,dstring,waitcnt)
	register char  *buffer;
	register char  *dstring;
	register int    waitcnt;
	{
	register int    i;
	register int    c;
	register int    countdown;

	i = 0;
	countdown = waitcnt;
	if (waitcnt >= 0)
	    printf ("(%2d) ", countdown);
	else
	    printf ("      ");
	while ((c=getchar(countval)) != '\n')
	    {
#ifdef PANEL
	    if (keypos == KEY_MAINT  &&  waitcnt >= 0)	/* Stop countdown if maint */
		{
		waitcnt = -1;
		printf ("\010\010\010\010\010    ");
		}
#endif PANEL
	    if (c == -2)
		{
		if (waitcnt >= 0)
		    {
		    countdown--;
		    printf ("\010\010\010\010%2d) ",
		      (countdown >= 0) ? countdown : 0);
		    }
		if (countdown >= 0  ||  waitcnt == -1)
		    {
		    continue;
		    }
		else
		    {
		    i = strlen(dstring);
		    bcopy(dstring,buffer,i);
		    puts(dstring);
		    c = '\n';
		    break;
		    }
		}
	    if (c == '\b')
		{
	    	if (i == 0)
		    {
		    printf("\007");
		    }
		else
		    {
		    printf("\b \b");
		    i--;
		    }
		}
#ifdef PANEL
	    else if (c < '\040'  ||  keypos == KEY_ON)
#else PANEL
	    else if (c < '\040')
#endif PANEL
		{
		putchar('\007');
		}
	    else
		{
		putchar(c);
		*(buffer + i++) = c;
		waitcnt = -1;
		}
	    }
	for (c = i;  --c >= 0;  )
	    putchar ('\010');
	printf ("\010\010\010\010\010    ");
	putchar ('\n');
	*(buffer + i) = '\0';
	}
