/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1987,1988
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */

#ifndef lint
static char    *rcsid = "$Header:rdump.c 12.0$";
#endif


#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "pcparam.h"
#include "rb.h"
#include "vars.h"


/*  rdump(addr,len,buff) Dump contents of Coprocessor memory to screen
 *  addr - unix addr
 *  len  - number of bytes to display
 *  buff - Address of buffer to use
 *
 */

extern char far *buff_dio;

int rdump(addr, len, buff)
	u_long          addr;
	u_short         len;
	char far       *buff;
{

	register u_short i, j;
	int             rc;

	rc = movein(addr, buff, len);

	if (rc < 0)
	{
		printf("rdump: Can't read memory, error code = %x\n", rc);
		return (rc);
	}
	i = 0;
	while (i < len)
	{
		printf("%8lx |", addr + i);

		for (j = 0; j < 16; j++)
		{
			printf("%2.2x", (u_short) buff[i + j] & 0xff);
			if (((j + 1) % 4) == 0)
				printf("  ");
		}

		printf("|  |");

		for (j = 0; j < 16; j++)
			if (buff[i + j] >= 'A' && buff[i + j] <= 'z')
				printf("%c", buff[i + j]);
			else
				putchar('.');

		printf("|\n");

		i += 16;
	}

	return (rc);
}


char           *cmds[] =
{
/* 1	 2	3	4	5	6	7	8 	9  	10 */
 "dump", "inp", "outp", "go", "help", "pcif", "debug", "quit", "change", "timer", 
/* 11 */
 "trace",
#if NCPU > 1
	 "cpu", "screen",
#endif
 (char *) 0
};
char           *cmdopts[] =
{
/*	1	 2	  3		4  5	6	7  8    9	*/
 "unixaddr len", "port", "port value", "", "", "", "flag", "", "addr value", 
 "",
#if NCPU > 1
 "number", "number",
#endif
 0
};
#define DUMP 1
#define INP  2
#define OUTP 3
#define GO   4
#define HELP 5
#define PCIF 6
#define DEBUG_CMD	7
#define QUIT	8
#define CHANGE	9
#define TIMER	10
#define PTRACE	11
#define CPU	12
#define SCREEN	13

void pcdebug()
{
	register int    i, j;
	int             argc;
	u_long          rompaddr;
	u_short         len, x, port;
	char            cbuff[120], cmd[20], arg1[20], arg2[20], *cptr;
	u_long		value;


	do
	{
		printf("Cmd  ===> ");
		gets(cbuff);
		argc = sscanf(cbuff, "%s %s %s", cmd, arg1, arg2);

		if (argc <= 0)
			i = HELP;
		else
		{
			j = strlen(cmd);
			i = 1;
			while ((cptr = cmds[i - 1]) != (char *) 0)
			{
				if (strncmp(cptr, cmd, j) == 0)
					break;
				i++;
			}
		}

		switch (i)
		{

		case GO:
			break;


		case DUMP:
			switch (argc)
			{
			case 1:
				printf("Unix Addr ==> ");
				gets(arg1);

			case 2:
				printf("Length ==> ");
				gets(arg2);

			default:
				break;
			}

			rompaddr = lcvttonum(arg1);
			len = cvttonum(arg2);
			rdump(rompaddr, len, buff_dio);
			break;

		case INP:
			if (argc < 2)
			{
				printf("Port ==> ");
				gets(arg1);
			}
			x = argc >= 3 ? cvttonum(arg2) : 1;
			port = cvttonum(arg1);
			for (;--x >= 0; ++port ) {
				j = IOIN(port);
				printf("Port %04x = %04x\n", port, j);
			}
			break;

		case OUTP:
			switch (argc)
			{
			case 1:
				printf("Port ==> ");
				gets(arg1);

			case 2:
				printf("Value ==> ");
				gets(arg2);

			default:
				break;
			}
			port = cvttonum(arg1);
			x = cvttonum(arg2);
			IOOUT(port, x);
			break;

		case PCIF:
			pcif_print();
			break;

		case DEBUG_CMD:
			if (argc < 2)
				printf("debug flags ==> ");
				gets(arg1);
			
			*dbugptr = lcvttonum(arg1);
			break;

		case QUIT:
			undo();
			exit(0);
			break;
		case CHANGE:
			switch (argc)
			{
			case 1:
				printf("Unix Addr ==> ");
				gets(arg1);

			case 2:
				printf("Value ==> ");
				gets(arg2);

			default:
				break;
			}

			rompaddr = lcvttonum(arg1);
			value = lcvttonum(arg2);
			value = exchl(value);
			if (moveout(rompaddr, (char far *) &value, sizeof value) < 0)
				printf("couldn't moveout to %lx\n",rompaddr);
			break;

		case PTRACE:
			trace_print();
			break;
#if NCPU > 1
		case CPU:
			switch (argc)
			{
			case 1:
				printf("number ==> ");
				gets(arg1);
			}
			x = cvttonum(arg1);
			if (x < 0 || x >= ncpu)
			{
				printf("invalid cpu number %d\n",x);
				break;
			}
			printf("was %d\n",cur_cbcb->cpu);
			cur_cbcb = cbcbptr + x;
			break;
		case SCREEN:
			switch (argc)
			{
			case 1:
				printf("number ==> ");
				gets(arg1);
			}
			x = cvttonum(arg1);
			if (x < 0 || x >= ncpu)
			{
				printf("invalid cpu number %d\n",x);
				break;
			}
			printf("was %d\n",screen_cbcb->cpu);
			screen_cbcb = cbcbptr + x;
			break;
#endif

		case TIMER:
			switch (argc)
			{
			case 1:
				printf("Unix Addr ==> ");
				gets(arg1);

			case 2:
				printf("byte count ==> ");
				gets(arg2);

			default:
				break;
			}

			rompaddr = lcvttonum(arg1);
			x = cvttonum(arg2);
			do_timer(rompaddr,x);
			break;
		case HELP:
		default:
			j = 0;
			printf("\nValid commands are:\n");
			while ((cptr = cmds[j]) != (char *) 0 && cmdopts[j] != 0)
				printf("%s  %s\n", cptr, cmdopts[j++]);
			printf("Numbers with leading 0x are take to be hex\n");
			printf("all others are treated as decimal\n");
			break;

		}

	} while (i != GO);

}

do_timer(rompaddr,value)
long rompaddr;
int value;
{
	int i;
	int count = 1024;
	extern char far * buff_dio;

	printf("moveout %d bytes (%d times) to %lx ...",
		value, count, rompaddr, buff_dio);
	for (i=0; i<count; ++i)
		moveout(rompaddr, buff_dio, value);
	printf(" done\n");
	printf("movein %d bytes (%d times) to %lx ...",
		value, count, rompaddr, buff_dio);
	for (i=0; i<count; ++i)
		movein(rompaddr, buff_dio, value);
	printf(" done\n");
}

#define R_DIAG	11
#define P_WIND128 4
#define P_WIND512 5

extern u_short *pcif_base;

struct pcifinfo {
char	*text;		/* descriptive text */
char	*format;	/* format item */
int	offset;		/* offset into PC/IF */
char	*bformat;	/* %b format item */
} pcif_info[] = {
	{ "window pointer 0", "%x", R_WIND1, 0, },
	{ "window pointer 1", "%x", R_WIND2, 0, },
	{ "window pointer 2", "%x", R_WIND3, 0, },
	{ "window pointer 3", "%x", R_WIND4, 0, },
	{ "128kb window ptr", "%x", P_WIND128, 0, },
	{ "512kb window ptr", "%x", P_WIND512, 0, },
	{ "pcif control",	"%b", P_CTRL, "\20\1BUFF0\2BUFF1\3BUFF2\4BUFF3\5ECC-ENABLE\6DIAG\7WIND0&1\10WIND2&3" },
	{ "pcif status",	"%b", P_STAT, "\20\3MUL-BIT-ERR\5ILL-ADDR-MAP\6ILL-ROMP-ADDR\7ECC-CORRECTED\10IOCC-CHECK" },
	{ "system base addr",	"%x", P_BASE, 0 },
	{ "ecc",	"%x", P_ECCR, 0 },
	{ "pcif config status",	"%b", P_CONF, "\20\6PARITY-ENABLED\7TIMEOUT-COUNT-ENABLED\10AT-MODE" },
	{ "romp diagnostics",	"%b", R_DIAG, "\20\10HOLD-RSC-STATUS" },
	{ "~romp clock",	"%b", R_CLOCK, "\20\1TIT3-DISABLE\2SCAN-GATE\3REG-FILE-READ\4INSTN-STOP-ENABLE\5ROMPC-STEP\6DEBUG-STOP\7ROMPC-RESET\10POR" },
	{ "romp control",	"%b", R_CTRL, "\20\1INT-ENABLE\2INT-REQUEST\4INTERLEAVED\6MASTER-MODE\7IPL\10HOLD-RSC" },
	{ "romp interrrupt",	"%b", R_INTR, "\20\1INT7\2INT6\3INT5\4INT4\5INT3\6INT2\7INT1\10INT0" },
	{ "~romp status",	"%b", R_STAT, "\20\1STOP\2DGO\3INSTN-COMPLETE\4SYNC\5FAIL\6WAIT\7CLOCK-STOPPED\10IPL-READY" },
	{ 0, 0, 0, 0 }
};

/*
 * code to display current PC/IF status
 */
pcif_print()
{
	unsigned char info;
	struct pcifinfo *p;
	for (p=pcif_info; p->format; ++p) {
		printf("pcif register %2d @ inb %03x",
			p->offset, p->offset + cur_cbcb->port);
		printf(" (%-18s) = ", p->text);
		info = IOIN(cur_cbcb->port + p->offset);
		if (p->text[0] == '~')
			info = ~info;	/* complement the bits */
		if (p->format[1] == 'b') {
			printf("%x",info);
			bformat(info,p->bformat+1);
		} else
			printf(p->format, info, p->bformat);
		printf("\n");
	}
}

bformat(num, s)
	int num;
	register char *s;
{
	register int i, c;
	register int any = 0;

	if (num) {
		putchar('<');
		while (i = *s++) {
			if (num & (1 << (i - 1))) {
				if (any)
					putchar(',');
				any = 1;
				for (; (c = *s) > ' '; s++)
					putchar(c);
			} else for (; *s > ' '; s++);
		}
		putchar('>');
	}
}

