/*
* vhdl & pattern generation of grog
*/
#include <stdio.h>
#include MUT_H
#include "grog.h"

static void vbe();
static void pat();

void grogvhdl(s, nb, nw, hz, r, msb, data)
long nb, nw, hz, r, msb;
biglong *data;
char *s;
{
FILE *f;

	if ((f = mbkfopen(s, "vbe", "w")) == NULL) {
		fprintf(stderr, "grog error : cannot open file %s.vbe\n", s);
		EXIT(2);
	}
	vbe(f, s, nw, nb, hz, r, msb, data);
	fclose(f);
}

void grogpat(s, nb, nw, hz, r, msb, data)
long nb, nw, hz, r, msb;
biglong *data;
char *s;
{
FILE *f;

	if ((f = mbkfopen(s, "pat", "w")) == NULL) {
		fprintf(stderr, "grog error : cannot open file %s.pat\n", s);
		EXIT(3);
	}
	pat(f, s, nw, nb, hz, r, msb, data);
	fclose(f);
}

char *long_hex(s, i, n)
char *s;
long i, n;
{
static char hexa[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
								'a', 'b', 'c', 'd', 'e', 'f' };
long j, k, l;

	l = (n >> 2) + ((n % 4) == 0 ? 0 : 1);
	*(s + l) = '\0'; /* end of string */
	for (j = 0xF, k = 0; k < l; k ++, j <<= 4)
		*(s + l - k - 1) = hexa[(i & j) >> (k << 2)];
	return s;
}

char *long_bin(s, i, n)
char *s;
long i, n;
{
long j, k;

	*(s + n) = '\0'; /* end of string */
	for (j = 1, k = 0; k < n; k++, j <<= 1)
		*(s + n - k - 1) = (i & j) ? '1' : '0';
	return s;
} 

char *biglong_hex(s, i, n)
char *s;
biglong i;
long n;
{
static char hexa[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
								'a', 'b', 'c', 'd', 'e', 'f' };
long j, k, l;

	l = (n >> 2) + ((n % 4) == 0 ? 0 : 1);
	*(s + l) = '\0'; /* end of string */
	for (j = 0xF, k = 0; k < l; k ++, j <<= 4) {
		if (k == 32) /* reset the mask value when switching word */
			j = 0xF;
		if (k < 32)
			*(s + l - k - 1) = hexa[(i.low & j) >> (k << 2)];
		else
			*(s + l - k - 1) = hexa[(i.high & j) >> (k << 2)];
	}
	return s;
}

char *biglong_bin(s, i, n)
char *s;
biglong i;
long n;
{
long j, k;

	*(s + n) = '\0'; /* end of string */
	for (j = 1, k = 0; k < n; k++, j <<= 1) {
		if (k == 32) /* reset the mask value when switching word */
			j = 1;
		if (k < 32)
			*(s + n - k - 1) = (i.low & j) ? '1' : '0';
		else
			*(s + n - k - 1) = (i.high & j) ? '1' : '0';
	}

	return s;
} 

static void vbe(f, s, nw, nb, hz, r, msb, data)
FILE *f;
char *s;
long nw, nb, hz, r, msb;
biglong *data;
{
long lnw = ln2p(nw); /* number of address lines */
char t[256], u[256]; /* max word and bit number */
long i, j, space, full = 0;
int hexa = 0;
char prefix = ' ';
char *(*long_string)(), *(*biglong_string)();
biglong v; /* needed to hold temporary static values to be passed to functions */

	for (i = 64; i <= 4096; i <<= 1)
		if (nw == i) { /* it is a power of 2 in the good range */
			full = 1;
			break;
		}
	if (hexa) {
		long_string = long_hex;
		biglong_string = biglong_hex;
		prefix = 'X';
	} else {
		long_string = long_bin;
		biglong_string = biglong_bin;
		prefix = 'B';
	}
	fputs("-- VHDL grog description\n", f);
	fprintf(f, "-- word number      : %d\n", nw);
	fprintf(f, "-- bit number       : %d\n", nb);
	fprintf(f, "-- tri-state output : %s\n", hz ? "yes" : "no");
	fputs("-- package to be used outside of cao-vlsi simulator\n", f);
	fputs("-- LIBRARY pkg;\n", f);
	fputs("-- USE pkg.p6b_pkg.all;\n", f);
	fprintf(f, "\n");
	fprintf(f, "\n");
	fprintf(f, "ENTITY %s IS\n", s);
	if (!msb)
	fprintf(f, "  PORT( adr  : IN BIT_VECTOR(%d DOWNTO 0);\n", lnw - 1);
	else
	fprintf(f, "  PORT( adr  : IN BIT_VECTOR(0 TO %d);\n", lnw - 1);
   if (nw == 64)
	fprintf(f, "        ck   : IN BIT;\n");
   else if (nw == 128 || nw == 256)
	fprintf(f, "        ck   : IN BIT_VECTOR(0 TO 1);\n");
	else
	fprintf(f, "        ck   : IN BIT_VECTOR(0 TO %d);\n", nw / 1025);
	if (hz)
	fprintf(f, "        oe   : IN BIT;\n");
	fprintf(f, "        f    : OUT BIT_VECTOR(0 TO %d);\n", nb - 1);
	fprintf(f, "        vdd  : IN BIT;\n");
	fprintf(f, "        vss  : IN BIT );\n");
	fprintf(f, "END %s;\n", s);
	fprintf(f, "\n");
	fprintf(f, "\n");
	fprintf(f, "ARCHITECTURE dataflow OF %s IS\n", s);
	fprintf(f, "  SIGNAL m_out : BIT_VECTOR (0 TO %d);\n", nb - 1);
	if (hz)
	fprintf(f, "  SIGNAL hz_in : BIT_VECTOR (0 TO %d);\n", nb - 1);
	fprintf(f, "\n");
	fprintf(f, "BEGIN\n");
   if (nw == 64)
	sprintf(t, "0");
   else if (nw == 128 || nw == 256)
	sprintf(t, "00");
	else
   for (t[0] = '\0', i = 0; i < nw / 512; i += 2)
   strcat(t, "0");
	if (!hz) {
	v.low = v.high = nw == 64 || nw == 128 ? ~0 : 0;
	fprintf(f, "   f     <= m_out WHEN (ck = B\"%s\") ELSE\n", t);
	fprintf(f, "            %c\"%s\";\n", prefix, biglong_string(u, v, nb));
	} else {
	v.low = v.high = 0;
	fprintf(f, "   f     <= hz_in WHEN (oe = '1') ELSE\n");
	fprintf(f, "            %c\"%s\";\n", prefix, biglong_string(u, v, nb));
	fprintf(f, "   hz_in <= m_out WHEN (ck = B\"%s\") ELSE\n", t);
	fprintf(f, "            %c\"%s\";\n", prefix, biglong_string(u, v, nb));
	}
	fprintf(f, "\n");
	if (!msb)
	fprintf(f, "   WITH adr(%d DOWNTO 0) SELECT\n", lnw - 1);
	else
	fprintf(f, "   WITH adr(0 TO %d) SELECT\n", lnw - 1);
	if (!r)
	space = fprintf(f, "      m_out(0 TO %d) <= ", nb - 1);
	else
	space = fprintf(f, "      m_out(%d DOWNTO 0) <= ", nb - 1);
	for (i = 0; i < nw; i++)
	if (i == 0)
	fprintf(f, "%c\"%s\" WHEN %c\"%s\",\n",
					prefix, biglong_string(t, data[i], nb),
					prefix, long_string(u, i, lnw));
	else if (i == nw - 1 && full) {
	for (j = 0; j < space; j++)
		putc(' ', f);
	fprintf(f, "%c\"%s\" WHEN %c\"%s\";\n",
					prefix, biglong_string(t, data[i], nb),
					prefix, long_string(u, i, lnw));
	} else {
	for (j = 0; j < space; j++)
		putc(' ', f);
	fprintf(f, "%c\"%s\" WHEN %c\"%s\",\n",
					prefix, biglong_string(t, data[i], nb),
					prefix, long_string(u, i, lnw));
	}
	if (!full) {
	for (j = 0; j < space; j++)
		putc(' ', f);
	fprintf(f, "%c\"%s\" WHEN OTHERS;\n",
						prefix, long_string(u, 0, nb));
	}

	fprintf(f, "\n");
	fprintf(f, "  ASSERT (vss = '0')\n");
	fprintf(f, "  REPORT   \"Power supply is missing on vss\"\n");
	fprintf(f, "  SEVERITY ERROR;\n");
	fprintf(f, "  ASSERT (vdd = '1')\n");
	fprintf(f, "  REPORT   \"Power supply is missing on vdd\"\n");
	fprintf(f, "  SEVERITY ERROR;\n");
	fprintf(f, "\n");
	fprintf(f, "END dataflow;\n");
}

static void pat(f, s, nw, nb, hz, r, msb, data)
FILE *f;
char *s;
long nw, nb, hz, r, msb;
biglong *data;
{
long lnw = ln2p(nw); /* number of address lines */
char t[256];
long i, j, k, l;
biglong v; /* needed to hold temporary static values to be passed to functions */

	fprintf(f, "# patterns for rom : %s test\n", s);
	if (!msb)
	fprintf(f, "in    adr(%d downto 0);;\n", lnw - 1);
	else
	fprintf(f, "in    adr(0 to %d);;\n", lnw - 1);
   if (nw == 64)
	fprintf(f, "in    ck;;\n");
   else if (nw == 128 || nw == 256)
	fprintf(f, "in    ck(0 to 1);;\n");
	else
   fprintf(f, "in    ck(0 to %d);;\n", nw / 1025);
	if (hz)
	fprintf(f, "in    oe;;\n");
	if (!r)
	fprintf(f, "out   f(0 to %d);;\n", nb - 1);
	else
	fprintf(f, "out   f(%d downto 0);;\n", nb - 1);
	fprintf(f, "in    vdd;;\n");
	fprintf(f, "in    vss;\n");
	fputs("begin\n", f);
	for (l = 0, i = 0; i < nw; i++) {
	for (k = 0; k < 2; k++) { /* clock pulse */
	fprintf(f, "pat%04d : ", l++);
	fprintf(f, "%s ", long_bin(t, i, lnw)); /* adr */
   if (nw == 64)
	fprintf(f, "%d ", k); /* ck */
   else if (nw == 128 || nw == 256)
	fprintf(f, "%d%d ", k, k); /* ck */
	else {
   for (j = 0; j < nw / 512; j += 2)
   fprintf(f, "%d", k);
   fprintf(f, " ");
	}
	if (hz)
	fprintf(f, "%d ", 1); /* hz */
	if (k == 0)
	fprintf(f, "?%s ", biglong_bin(t, data[i], nb)); /* f */
	else {
	v.low = v.high = !hz && (nw == 64 || nw == 128) ? ~0 : 0;
	fprintf(f, "?%s ", biglong_bin(t, v, nb));
	}
	fprintf(f, "%d ", 1); /* vdd */
	fprintf(f, "%d;\n", 0); /* vss */
	}
	}
	fputs("end;\n", f);
}
