/* Copyright (c)1994-2000 Begemot Computer Associates. All rights reserved.
 * See the file COPYRIGHT for details of redistribution and use. */

/*
 * Dump a p11 image file in ascii.
 *
 * $Id: idump.c 476 2001-07-09 08:09:10Z hbb $
 */
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <errno.h>
# include <string.h>
# include <begemot.h>
# include <netinet/in.h>
# ifdef HAVE_GETOPT_H
#  include <getopt.h>
# endif

# include "../cdefs.h"
# include "../bits.h"

typedef struct hdr1_t {
	u_short	regs[8];
	u_short	set0[6];
	u_short	set1[6];
	u_short	sp[4];
	u_short	psw;
	u_int	maxmem;
	u_short	mmr[4];
	u_short	merror, cache, hitmiss;
	u_short	par[4][2][8];
	u_short	pdr[4][2][8];
} hdr1_t;

static u_short	read_version(void);
static hdr1_t	*read1_header(void);
static void	dump1_header(hdr1_t *);
static void	dump1_memory(hdr1_t *);

static void	print_psw(u_short);
static void	print_regs(u_short *, u_int);
static void	print_mmr(u_short *);
static void	print_par(u_short [2][8], u_short [2][8]);
static void	print_1par(u_short, u_short);

static char usgtxt[] =
"p11 image dumper $Revision: 476 $; Copyright(c)1994-2000 Begemot Computer Assicates.\n"
"Usage: idump [-h] [file]\n"
"where:\n"
" -h	print this info\n";

static void usage(void) DEAD_FUNC;


static int	mflag;

int
main(int argc, char *argv[])
{
	int opt;
	u_short v;

	set_argv0(argv[0]);
	while((opt = getopt(argc, argv, "hm")) != EOF)
		switch(opt) {

		  case 'h':
			usage();

		  case 'm':
			mflag = 1;
			break;
		}

	argc -= optind;
	argv += optind;

	if(argc > 0)
		if(freopen(argv[0], "r", stdin) == NULL)
			panic("%s: %s", argv[0], strerror(errno));

	switch(v = read_version()) {

	  case 1: {
			hdr1_t *hdr1 = read1_header();

			dump1_header(hdr1);
			if(mflag)
				dump1_memory(hdr1);
		}
		break;

	  default:
		panic("image version %d not supported", v);
	}

	return 0;
}

static void
usage(void)
{
	fprintf(stderr, "%s", usgtxt);
	exit(0);
}

static u_short
read_version(void)
{
	u_short s;

	if(fread(&s, sizeof(u_short), 1, stdin) != 1)
		panic("reading version: %s", strerror(errno));
	return ntohs(s);
}

# define DUMP1_HDRLEN (27+96+7)

static hdr1_t *
read1_header(void)
{
	hdr1_t *h;
	u_short	hdr[DUMP1_HDRLEN];
	u_int i;
	u_int off;

	if(fread(hdr, sizeof(u_short), DUMP1_HDRLEN, stdin) != DUMP1_HDRLEN)
		panic("reading header: %s", strerror(errno));

	h = xalloc(sizeof(hdr1_t));

# define MOVE(T,N) for(i = 0; i < (N); i++) { h->T[i] = ntohs(hdr[off+i]); } off += N;

	off = 0;
	MOVE(regs, 8);
	MOVE(set0, 6);
	MOVE(set1, 6);
	MOVE(sp, 4);

	h->psw = ntohs(hdr[off]);
	off++;

	h->maxmem = (ntohs(hdr[off]) << 16) + ntohs(hdr[off+1]);
	off += 2;

	MOVE(mmr, 4);

	h->merror = ntohs(hdr[off]);
	off++;
	h->cache = ntohs(hdr[off]);
	off++;
	h->hitmiss = ntohs(hdr[off]);
	off++;

	MOVE(pdr[0][0], 8);
	MOVE(pdr[0][1], 8);
	MOVE(par[0][0], 8);
	MOVE(par[0][1], 8);

	MOVE(pdr[1][0], 8);
	MOVE(pdr[1][1], 8);
	MOVE(par[1][0], 8);
	MOVE(par[1][1], 8);

	MOVE(pdr[3][0], 8);
	MOVE(pdr[3][1], 8);
	MOVE(par[3][0], 8);
	MOVE(par[3][1], 8);

	if(off != DUMP1_HDRLEN)
		bug("off=%d", off);

	return h;
}

static void
dump1_header(hdr1_t *h)
{
	u_int i;

	printf("Version 1 image dump\n");

	printf("regs:");
	print_regs(h->regs, 8);
	printf("\n");

	printf("set0:");
	print_regs(h->set0, 6);
	printf("\n");

	printf("set1:");
	print_regs(h->set1, 6);
	printf("\n");

	printf("stacks:");
	for(i = 0; i < 4; i++)
		if(i != 2)
			printf(" %cSP=%06o", "KSXU"[i], h->sp[i]);
	printf("\n");

	printf("psw:");
	print_psw(h->psw);
	printf("\n");

	print_mmr(h->mmr);

	printf("kernel space:\n");
	print_par(h->par[0], h->pdr[0]);
	printf("supervisor space:\n");
	print_par(h->par[1], h->pdr[1]);
	printf("user space:\n");
	print_par(h->par[3], h->pdr[3]);

	printf("mem:");
	printf(" MAXMEM=%09o\n", h->maxmem);
}


static void
print_regs(u_short *r, u_int cnt)
{
	u_int i;

	for(i = 0; i < cnt; i++)
		printf(" R%d=%06o", i, r[i]);
}

static void
print_psw(u_short psw)
{
	printf(" PSW=%06o CMODE=%c PMODE=%c R=%d PRI=%d T=%d N=%d Z=%d V=%d C=%d",
		psw, "KSXU"[(psw >> 14) & 3], "KSXU"[(psw >> 12) & 3],
		(psw >> 11) & 1, (psw >> 5) & 7, (psw >> 4) & 1,
		(psw >> 3) & 1, (psw >> 2) & 1, (psw >> 1) & 1, (psw >> 0) & 1);
}

static void
print_mmr(u_short *mmr)
{
	short chg1, chg0;

	printf("mmr0: %06o %s%s%s%sTRAP=(%c %c %1o) %s\n", *mmr,
		(*mmr & MMR0_ANR) ? "ANR " : "",
		(*mmr & MMR0_APL) ? "APL " : "",
		(*mmr & MMR0_ARO) ? "ARO " : "",
		(*mmr & MMR0_MAI) ? "MAI " : "",
		"KSXU"[(*mmr & MMR0_MODE) >> MMR0_MODE_SHIFT],
		"ID"[(*mmr & MMR0_SPACE) != 0],
		(*mmr & MMR0_PAGE) >> MMR0_PAGE_SHIFT,
		(*mmr & MMR0_ENABLE) ? "ENABLED" : "DISABLED");
	mmr++;

	chg0 = (*mmr >> 3) & 037;
	if(chg0 & 020)
		chg0 = -((~chg0 & 037) + 1);
	chg1 = (*mmr >> 11) & 037;
	if(chg1 & 020)
		chg1 = -((~chg1 & 037) + 1);
	printf("mmr1: %06o dst=%1o(%d) src=%1o(%d)\n", *mmr,
		(*mmr >> 8) & 7, chg1,
		(*mmr >> 0) & 7, chg0);
	mmr++;

	printf("mmr2: %06o\n", *mmr++);

	printf("mmr3: %06o %s%s%s%s%s\n", *mmr,
		(*mmr & MMR3_IOM) ? "IOM " : "",
		(*mmr & MMR3_KSEP) ? "KSEP " : "",
		(*mmr & MMR3_SSEP) ? "SSEP " : "",
		(*mmr & MMR3_USEP) ? "USEP " : "",
		(*mmr & MMR3_22B) ? "22bit" : "not-22bit");
}

static void
print_par(u_short par[2][8], u_short pdr[2][8])
{
	u_int i, s;

	for(i = 0; i < 8; i++) {
		for(s = 0; s < 2; s++) {
			if(s == 1)
				printf("   ");
			print_1par(par[s][i], pdr[s][i]);
		}
		printf("\n");
	}
}

static void
print_1par(u_short par, u_short pdr)
{
	printf("%06o %06o ", par, pdr);
	printf("%s ", (pdr & PDR_STACK) ? "ST" : "  ");

	switch(pdr & (PDR_RES|PDR_RW)) {

	  case 0:
		printf("-- ");
		break;

	  case PDR_RES:
		printf("RO ");
		break;

	  case PDR_RES|PDR_RW:
		printf("RW ");
		break;

	  case PDR_RW:
		printf("XX ");
		break;
	}

	if(pdr & PDR_RES) {
		if(pdr & PDR_STACK)
			printf("%08o-%08o",
				(par<<6)+((pdr&PDR_LEN)>>(PDR_LEN_SHIFT-6)),
				(par<<6)+020000);
		else
			printf("%08o-%08o",
				(par<<6),
				(par<<6)+((pdr&PDR_LEN)>>(PDR_LEN_SHIFT-6))+0100);
	} else
		printf("                 ");
}

static void
dump1_memory(hdr1_t *h)
{
	u_short *m;
	u_int a;

	m = xalloc(sizeof(u_short) * (h->maxmem >> 1));
	if(fread(m, sizeof(u_short), h->maxmem >> 1, stdin) != h->maxmem >> 1)
		panic("reading memory: %s", strerror(errno));

	for(a = 0; a < h->maxmem; a += 2) {
		if(a % 16 == 0)
			printf("%09o ", a);
		printf(" %06o", m[a >> 1]);
		if(a % 16 == 14)
			printf("\n");
	}
	if(a % 16 != 0)
		printf("\n");
	else
		printf("%09o\n", a);

	free(m);
}
