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
- Lines: 644
- Date:
Thu Jun 29 11:19:10 1995
- Orig file:
v1.3.4/linux/drivers/scsi/aic7xxx_asm.c
- Orig date:
Thu Jan 1 02:00:00 1970
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