patch-1.3.5 linux/drivers/scsi/aic7xxx_asm.c

Next file: linux/drivers/scsi/buslogic.c
Previous file: linux/drivers/scsi/aic7xxx.seq
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v1.3.4/linux/drivers/scsi/aic7xxx_asm.c linux/drivers/scsi/aic7xxx_asm.c
@@ -0,0 +1,643 @@
+/*+M*************************************************************************
+ * Adaptec AIC7770/AIC7870 sequencer code assembler.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *   All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by the University of Calgary
+ *      Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Comments are started by `#' and continue to the end of the line; lines
+ * may be of the form:
+ *      <label>*
+ *      <label>*  <undef-sym> = <value>
+ *      <label>*  <opcode> <operand>*
+ *
+ * A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
+ * are token separators.
+ *
+ *-M*************************************************************************/
+static char id[] = "$Id: aic7xxx_asm.c,v 1.8 1995/05/25 06:25:36 root Exp $";
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MEMORY		448
+#define MAXLINE		1024
+#define MAXTOKEN	32
+#define ADOTOUT		"a.out"
+#define NOVALUE		-1
+
+/*
+ * AIC-7770/AIC-7870 register definitions
+ */
+#define R_SINDEX	0x65
+#define R_ALLONES	0x69
+#define R_ALLZEROS	0x6a
+#define R_NONE		0x6a
+
+int debug;
+int lineno, LC;
+char *filename;
+FILE *ifp, *ofp;
+unsigned char M[MEMORY][4];
+
+void 
+error(char *s)
+{
+	fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
+	exit(EXIT_FAILURE);
+}
+
+void *
+Malloc(size_t size)
+{
+	void *p = malloc(size);
+	if (!p)
+		error("out of memory");
+	return(p);
+}
+
+void *
+Realloc(void *ptr, size_t size)
+{
+	void *p = realloc(ptr, size);
+	if (!p)
+		error("out of memory");
+	return(p);
+}
+
+char *
+Strdup(char *s)
+{
+	char *p = (char *)Malloc(strlen(s) + 1);
+	strcpy(p, s);
+	return(p);
+}
+
+typedef struct sym_t {
+	struct sym_t	*next;		/* MUST BE FIRST */
+	char		*name;
+	int		value;
+	int		npatch; 
+	int		*patch;
+} sym_t;
+
+sym_t *head;
+
+void
+define(char *name, int value)
+{
+	sym_t *p, *q;
+
+	for (p = head, q = (sym_t *)&head; p; p = p->next) {
+		if (!strcmp(p->name, name))
+			error("redefined symbol");
+		q = p;
+	}
+
+	p = q->next = (sym_t *)Malloc(sizeof(sym_t));
+	p->next = NULL;
+	p->name = Strdup(name);
+	p->value = value;
+	p->npatch = 0;
+	p->patch = NULL;
+
+	if (debug) {
+		fprintf(stderr, "\"%s\" ", p->name);
+		if (p->value != NOVALUE)
+			fprintf(stderr, "defined as 0x%x\n", p->value);
+		else
+			fprintf(stderr, "undefined\n");
+	}
+}
+
+sym_t *
+lookup(char *name)
+{
+	sym_t *p;
+
+	for (p = head; p; p = p->next)
+		if (!strcmp(p->name, name))
+			return(p);
+	return(NULL);
+}
+
+void 
+patch(sym_t *p, int location)
+{
+	p->npatch += 1;
+	p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
+
+	p->patch[p->npatch - 1] = location;
+}
+
+void backpatch(void)
+{
+	int i;
+	sym_t *p;
+
+	for (p = head; p; p = p->next) {
+
+		if (p->value == NOVALUE) {
+			fprintf(stderr,
+				"%s: undefined symbol \"%s\"\n",
+				filename, p->name);
+			exit(EXIT_FAILURE);
+		}
+
+		if (p->npatch) {
+			if (debug)
+				fprintf(stderr,
+					"\"%s\" (0x%x) patched at",
+					p->name, p->value);
+
+			for (i = 0; i < p->npatch; i++) {
+				M[p->patch[i]][0] &= ~1;
+				M[p->patch[i]][0] |= ((p->value >> 8) & 1);
+				M[p->patch[i]][1] = p->value & 0xff;
+
+				if (debug)
+					fprintf(stderr, " 0x%x", p->patch[i]);
+			}
+
+			if (debug)
+				fputc('\n', stderr);
+		}
+	}
+}
+
+/*
+ *  Output words in byte-reversed order (least significant first)
+ *  since the sequencer RAM is loaded that way.
+ */
+void
+output(FILE *fp)
+{
+	int i;
+
+	for (i = 0; i < LC; i++)
+		fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
+			M[i][3],
+			M[i][2],
+			M[i][1],
+			M[i][0]);
+	printf("%d out of %d instructions used.\n", LC, MEMORY);
+}
+
+char **
+getl(int *n)
+{
+	int i;
+	char *p, *quote;
+	static char buf[MAXLINE];
+	static char *a[MAXTOKEN];
+
+	i = 0;
+
+	while (fgets(buf, sizeof(buf), ifp)) {
+
+		lineno += 1;
+
+		if (buf[strlen(buf)-1] != '\n')
+			error("line too long");
+
+		p = strchr(buf, '#');
+		if (p)
+			*p = '\0';
+		p = buf;
+rescan:
+		quote = strchr(p, '\"');
+		if (quote)
+			*quote = '\0';
+		for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
+			if (i < MAXTOKEN-1)
+				a[i++] = p;
+			else
+				error("too many tokens");
+		if (quote) {
+			quote++; 
+			p = strchr(quote, '\"');
+			if (!p)
+				error("unterminated string constant");
+			else if (i < MAXTOKEN-1) {
+				a[i++] = quote;
+				*p = '\0';
+				p++;
+			}
+			else
+				error("too many tokens");
+			goto rescan;
+		}		
+		if (i) {
+			*n = i;
+			return(a);
+		}
+	}
+	return(NULL);
+}
+
+#define A	0x8000		/* `A'ccumulator ok */
+#define I	0x4000		/* use as immediate value */
+#define SL	0x2000		/* shift left */
+#define SR	0x1000		/* shift right */
+#define RL	0x0800		/* rotate left */
+#define RR	0x0400		/* rotate right */
+#define LO	0x8000		/* lookup: ori-{jmp,jc,jnc,call} */
+#define LA	0x4000		/* lookup: and-{jz,jnz} */
+#define LX	0x2000		/* lookup: xor-{je,jne} */
+#define NA	-1		/* not applicable */
+
+struct {
+	char *name;
+	int n;			/* number of operands, including opcode */
+	unsigned int op;	/* immediate or L?|pos_from_0 */
+	unsigned int dest;	/* NA, pos_from_0, or I|immediate */
+	unsigned int src;	/* NA, pos_from_0, or I|immediate */
+	unsigned int imm;	/* pos_from_0, A|pos_from_0, or I|immediate */
+	unsigned int addr;	/* NA or pos_from_0 */
+	int fmt;		/* instruction format - 1, 2, or 3 */
+} instr[] = {
+/*
+ *		  N  OP    DEST		SRC		IMM	ADDR	FMT
+ */
+	{ "mov",  3, 1,	   1,		2,		I|0xff,	NA,	1 },
+	{ "mov",  4, LO|2, NA,		1,		I|0,	3,	3 },
+	{ "mvi",  3, 0,	   1,		I|R_ALLZEROS,	A|2,	NA,	1 },
+	{ "mvi",  4, LO|2, NA,		I|R_ALLZEROS,	1,	3,	3 },
+	{ "not",  2, 2,	   1,		1,		I|0xff,	NA,	1 },
+	{ "and",  3, 1,	   1,		1,		A|2,	NA,	1 },
+	{ "and",  4, 1,	   1,		3,		A|2,	NA,	1 },
+	{ "or",	  3, 0,	   1,		1,		A|2,	NA,	1 },
+	{ "or",	  4, 0,	   1,		3,		A|2,	NA,	1 },
+	{ "or",   5, LO|3, NA,		1,		2,	4,	3 },
+	{ "xor",  3, 2,	   1,		1,		A|2,	NA,	1 },
+	{ "xor",  4, 2,	   1,		3,		A|2,	NA,	1 },
+	{ "nop",  1, 1,	   I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
+	{ "inc",  2, 3,	   1,		1,		I|1,	NA,	1 },
+	{ "inc",  3, 3,	   1,		2,		I|1,	NA,	1 },
+	{ "dec",  2, 3,	   1,		1,		I|0xff,	NA,	1 },
+	{ "dec",  3, 3,	   1,		2,		I|0xff,	NA,	1 },
+	{ "jmp",  2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
+	{ "jc",   2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
+	{ "jnc",  2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
+	{ "call", 2, LO|0,   NA,	I|R_SINDEX,	I|0,	1,	3 },
+	{ "test", 5, LA|3,   NA,	1,		A|2,	4,	3 },
+	{ "cmp",  5, LX|3,   NA,	1,		A|2,	4,	3 },
+	{ "ret",  1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
+	{ "ret",  1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,	1 },
+	{ "clc",  1, 3,	 I|R_NONE,	I|R_ALLZEROS,	I|1,	NA,	1 },
+	{ "clc",  4, 3,	 2,		I|R_ALLZEROS,	A|3,	NA,	1 },
+	{ "stc",  2, 3,	 1,		I|R_ALLONES,	I|1,	NA,	1 },
+	{ "add",  3, 3,	 1,		1,		A|2,	NA,	1 },
+	{ "add",  4, 3,	 1,		3,		A|2,	NA,	1 },
+	{ "adc",  3, 4,	 1,		1,		A|2,	NA,	1 },
+	{ "adc",  4, 4,	 1,		3,		A|2,	NA,	1 },
+	{ "shl",  3, 5,	 1,		1,		SL|2,	NA,	2 },
+	{ "shl",  4, 5,	 1,		2,		SL|3,	NA,	2 },
+	{ "shr",  3, 5,	 1,		1,		SR|2,	NA,	2 },
+	{ "shr",  4, 5,	 1,		2,		SR|3,	NA,	2 },
+	{ "rol",  3, 5,	 1,		1,		RL|2,	NA,	2 },
+	{ "rol",  4, 5,	 1,		2,		RL|3,	NA,	2 },
+	{ "ror",  3, 5,	 1,		1,		RR|2,	NA,	2 },
+	{ "ror",  4, 5,	 1,		2,		RR|3,	NA,	2 },
+	/*
+	 *  Extensions (note also that mvi allows A)
+	 */
+ 	{ "clr",  2, 1,	 1,	I|R_ALLZEROS,		I|0xff,	NA,	1 },
+	{ 0,      0, 0,  0, 	0,			0,	0,	0 }
+};
+
+int 
+eval_operand(char **a, int spec)
+{
+	int i;
+	unsigned int want = spec & (LO|LA|LX);
+
+	static struct {
+		unsigned int what;
+		char *name;
+		int value;
+	} jmptab[] = {
+		{ LO,	"jmp",		8  },
+		{ LO,	"jc",		9  },
+		{ LO,	"jnc",		10 },
+		{ LO,	"call",		11 },
+		{ LA,	"jz",		15 },
+		{ LA,	"jnz",		13 },
+		{ LX,	"je",		14 },
+		{ LX,	"jne",		12 },
+	};
+
+	spec &= ~(LO|LA|LX);
+
+	for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
+		if (jmptab[i].what == want &&
+		    !strcmp(jmptab[i].name, a[spec]))
+		{
+			return(jmptab[i].value);
+		}
+
+	if (want)
+		error("invalid jump");
+
+	return(spec);		/* "case 0" - no flags set */
+}
+
+int
+eval_sdi(char **a, int spec)
+{
+	sym_t *p;
+	unsigned val;
+
+	if (spec == NA)
+		return(NA);
+
+	switch (spec & (A|I|SL|SR|RL|RR)) {
+	    case SL:
+	    case SR:
+	    case RL:
+	    case RR:
+		if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
+			val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
+		else {
+			p = lookup(a[spec &~ (SL|SR|RL|RR)]);
+			if (!p)
+				error("undefined symbol used");
+			val = p->value;
+		}
+
+		switch (spec & (SL|SR|RL|RR)) {		/* blech */
+		    case SL:
+			if (val > 7)
+				return(0xf0);
+			return(((val % 8) << 4) |
+			       (val % 8));
+		    case SR:
+			if (val > 7)
+				return(0xf0);
+			return(((val % 8) << 4) |
+			       (1 << 3) |
+			       ((8 - (val % 8)) % 8));
+		    case RL:
+			return(val % 8);
+		    case RR:
+			return((8 - (val % 8)) % 8);
+		}
+	    case I:
+		return(spec &~ I);
+	    case A:
+		/*
+		 *  An immediate field of zero selects
+		 *  the accumulator.  Vigorously object
+		 *  if zero is given otherwise - it's
+		 *  most likely an error.
+		 */
+		spec &= ~A;
+		if (!strcmp("A", a[spec]))
+			return(0);
+		if (isdigit(*a[spec]) &&
+		    strtol(a[spec], NULL, 0) == 0)
+		{
+			error("immediate value of zero selects accumulator");
+		}
+		/* falls through */
+	    case 0:
+		if (isdigit(*a[spec]))
+			return(strtol(a[spec], NULL, 0));
+		p = lookup(a[spec]);
+		if (p)
+			return(p->value);
+		error("undefined symbol used");
+	}
+
+	return(NA);		/* shut the compiler up */
+}
+
+int
+eval_addr(char **a, int spec)
+{
+	sym_t *p;
+
+	if (spec == NA)
+		return(NA);
+	if (isdigit(*a[spec]))
+		return(strtol(a[spec], NULL, 0));
+
+	p = lookup(a[spec]);
+
+	if (p) {
+		if (p->value != NOVALUE)
+			return(p->value);
+		patch(p, LC);
+	} else {
+		define(a[spec], NOVALUE);
+		p = lookup(a[spec]);
+		patch(p, LC);
+	}
+
+	return(NA);		/* will be patched in later */
+}
+
+int
+crack(char **a, int n)
+{
+	int i;
+	int I_imm, I_addr;
+	int I_op, I_dest, I_src, I_ret;
+
+	/*
+	 *  Check for "ret" at the end of the line; remove
+	 *  it unless it's "ret" alone - we still want to
+	 *  look it up in the table.
+	 */
+	I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
+	if (I_ret && n > 1)
+		n -= 1;
+
+	for (i = 0; instr[i].name; i++) {
+		/*
+		 *  Look for match in table given constraints,
+		 *  currently just the name and the number of
+		 *  operands.
+		 */
+		if (!strcmp(instr[i].name, *a) && instr[i].n == n)
+			break;
+	}
+	if (!instr[i].name)
+		error("unknown opcode or wrong number of operands");
+
+	I_op	= eval_operand(a, instr[i].op);
+	I_src	= eval_sdi(a, instr[i].src);
+	I_imm	= eval_sdi(a, instr[i].imm);
+	I_dest	= eval_sdi(a, instr[i].dest);
+	I_addr	= eval_addr(a, instr[i].addr);
+
+	if( LC >= MEMORY )
+		error("Memory exhausted!\n");
+
+	switch (instr[i].fmt) {
+	    case 1:
+	    case 2:
+		M[LC][0] = (I_op << 1) | I_ret;
+		M[LC][1] = I_dest;
+		M[LC][2] = I_src;
+		M[LC][3] = I_imm;
+		break;
+	    case 3:
+		if (I_ret)
+			error("illegal use of \"ret\"");
+		M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
+		M[LC][1] = I_addr & 0xff;
+		M[LC][2] = I_src;
+		M[LC][3] = I_imm;
+		break;
+	}
+
+	return (1);		/* no two-byte instructions yet */
+}
+
+#undef SL
+#undef SR
+#undef RL
+#undef RR
+#undef LX
+#undef LA
+#undef LO
+#undef I
+#undef A
+
+void
+assemble(void)
+{
+	int n;
+	char **a;
+	sym_t *p;
+
+	while ((a = getl(&n))) {
+
+		while (a[0][strlen(*a)-1] == ':') {
+			a[0][strlen(*a)-1] = '\0';
+			p = lookup(*a);
+			if (p)
+				p->value = LC;
+			else
+				define(*a, LC);
+			a += 1;
+			n -= 1;
+		}
+
+		if (!n)			/* line was all labels */
+			continue;
+
+		if (n == 3 && !strcmp("VERSION", *a))
+			fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
+		else {
+			if (n == 3 && !strcmp("=", a[1]))
+				define(*a, strtol(a[2], NULL, 0));
+			else
+				LC += crack(a, n);
+		}
+	}
+
+	backpatch();
+	output(ofp);
+
+	if (debug)
+		output(stderr);
+}
+
+int
+main(int argc, char **argv)
+{
+	int c;
+
+	while ((c = getopt(argc, argv, "dho:vD")) != EOF) {
+		switch (c) {
+		    case 'd':
+			debug = !0;
+			break;
+		    case 'D':
+		    {
+			char *p;
+			if ((p = strchr(optarg, '=')) != NULL) {
+				*p = '\0';
+				define(optarg, strtol(p + 1, NULL, 0));
+			}
+			else
+				define(optarg, 1);
+			break;
+		    }
+		    case 'o':
+			ofp = fopen(optarg, "w");
+			if (!ofp) {
+				perror(optarg);
+				exit(EXIT_FAILURE);
+			}
+			break;
+		    case 'h':
+			printf("usage: %s [-d] [-Dname] [-ooutput] input\n", 
+				*argv);
+			exit(EXIT_SUCCESS);
+			break;
+		    case 'v':
+			printf("%s\n", id);
+			exit(EXIT_SUCCESS);
+			break;
+		    default:
+			exit(EXIT_FAILURE);
+			break;
+		}
+	}
+
+	if (argc - optind != 1) {
+		fprintf(stderr, "%s: must have one input file\n", *argv);
+		exit(EXIT_FAILURE);
+	}
+	filename = argv[optind];
+
+	ifp = fopen(filename, "r");
+	if (!ifp) {
+		perror(filename);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!ofp) {
+		ofp = fopen(ADOTOUT, "w");
+		if (!ofp) {
+			perror(ADOTOUT);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	assemble();
+	exit(EXIT_SUCCESS);
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov with Sam's (original) version
of this