xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm.c (revision a316b26e50bbed7cf655fbba726ab87d8ab7599d)
1 /*
2  * Adaptec 274x device driver for Linux.
3  * Copyright (c) 1994 The University of Calgary Department of Computer Science.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *  Comments are started by `#' and continue to the end of the line; lines
20  *  may be of the form:
21  *
22  *	<label>*
23  *	<label>*  <undef-sym> = <value>
24  *	<label>*  <opcode> <operand>*
25  *
26  *  A <label> is an <undef-sym> ending in a colon.  Spaces, tabs, and commas
27  *  are token separators.
28  */
29 
30 /* #define _POSIX_SOURCE	1 */
31 #define _POSIX_C_SOURCE	2
32 
33 #include <ctype.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 
39 #define MEMORY		512		/* 2^9 29-bit words */
40 #define MAXLINE		1024
41 #define MAXTOKEN	32
42 #define ADOTOUT		"a.out"
43 #define NOVALUE		-1
44 
45 /*
46  *  AIC-7770 register definitions
47  */
48 #define R_SINDEX	0x65
49 #define R_ALLONES	0x69
50 #define R_ALLZEROS	0x6a
51 #define R_NONE		0x6a
52 
53 static
54 char sccsid[] =
55     "@(#)aic7770.c 1.10 94/07/22 jda";
56 
57 int debug;
58 int lineno, LC;
59 char *filename;
60 FILE *ifp, *ofp;
61 unsigned char M[MEMORY][4];
62 
63 void error(char *s)
64 {
65 	fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
66 	exit(EXIT_FAILURE);
67 }
68 
69 void *Malloc(size_t size)
70 {
71 	void *p = malloc(size);
72 	if (!p)
73 		error("out of memory");
74 	return(p);
75 }
76 
77 void *Realloc(void *ptr, size_t size)
78 {
79 	void *p = realloc(ptr, size);
80 	if (!p)
81 		error("out of memory");
82 	return(p);
83 }
84 
85 char *Strdup(char *s)
86 {
87 	char *p = (char *)Malloc(strlen(s) + 1);
88 	strcpy(p, s);
89 	return(p);
90 }
91 
92 typedef struct sym_t {
93 	struct sym_t *next;		/* MUST BE FIRST */
94 	char *name;
95 	int value;
96 	int npatch, *patch;
97 } sym_t;
98 
99 sym_t *head;
100 
101 void define(char *name, int value)
102 {
103 	sym_t *p, *q;
104 
105 	for (p = head, q = (sym_t *)&head; p; p = p->next) {
106 		if (!strcmp(p->name, name))
107 			error("redefined symbol");
108 		q = p;
109 	}
110 
111 	p = q->next = (sym_t *)Malloc(sizeof(sym_t));
112 	p->next = NULL;
113 	p->name = Strdup(name);
114 	p->value = value;
115 	p->npatch = 0;
116 	p->patch = NULL;
117 
118 	if (debug) {
119 		fprintf(stderr, "\"%s\" ", p->name);
120 		if (p->value != NOVALUE)
121 			fprintf(stderr, "defined as 0x%x\n", p->value);
122 		else
123 			fprintf(stderr, "undefined\n");
124 	}
125 }
126 
127 sym_t *lookup(char *name)
128 {
129 	sym_t *p;
130 
131 	for (p = head; p; p = p->next)
132 		if (!strcmp(p->name, name))
133 			return(p);
134 	return(NULL);
135 }
136 
137 void patch(sym_t *p, int location)
138 {
139 	p->npatch += 1;
140 	p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
141 
142 	p->patch[p->npatch - 1] = location;
143 }
144 
145 void backpatch(void)
146 {
147 	int i;
148 	sym_t *p;
149 
150 	for (p = head; p; p = p->next) {
151 
152 		if (p->value == NOVALUE) {
153 			fprintf(stderr,
154 				"%s: undefined symbol \"%s\"\n",
155 				filename, p->name);
156 			exit(EXIT_FAILURE);
157 		}
158 
159 		if (p->npatch) {
160 			if (debug)
161 				fprintf(stderr,
162 					"\"%s\" (0x%x) patched at",
163 					p->name, p->value);
164 
165 			for (i = 0; i < p->npatch; i++) {
166 				M[p->patch[i]][0] &= ~1;
167 				M[p->patch[i]][0] |= ((p->value >> 8) & 1);
168 				M[p->patch[i]][1] = p->value & 0xff;
169 
170 				if (debug)
171 					fprintf(stderr, " 0x%x", p->patch[i]);
172 			}
173 
174 			if (debug)
175 				fputc('\n', stderr);
176 		}
177 	}
178 }
179 
180 /*
181  *  Output words in byte-reversed order (least significant first)
182  *  since the sequencer RAM is loaded that way.
183  */
184 void output(FILE *fp)
185 {
186 	int i;
187 
188 	for (i = 0; i < LC; i++)
189 		fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
190 			M[i][3],
191 			M[i][2],
192 			M[i][1],
193 			M[i][0]);
194 }
195 
196 char **getl(int *n)
197 {
198 	int i;
199 	char *p;
200 	static char buf[MAXLINE];
201 	static char *a[MAXTOKEN];
202 
203 	i = 0;
204 
205 	while (fgets(buf, sizeof(buf), ifp)) {
206 
207 		lineno += 1;
208 
209 		if (buf[strlen(buf)-1] != '\n')
210 			error("line too long");
211 
212 		p = strchr(buf, '#');
213 		if (p)
214 			*p = '\0';
215 
216 		for (p = strtok(buf, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
217 			if (i < MAXTOKEN-1)
218 				a[i++] = p;
219 			else
220 				error("too many tokens");
221 		if (i) {
222 			*n = i;
223 			return(a);
224 		}
225 	}
226 	return(NULL);
227 }
228 
229 #define A	0x8000		/* `A'ccumulator ok */
230 #define I	0x4000		/* use as immediate value */
231 #define SL	0x2000		/* shift left */
232 #define SR	0x1000		/* shift right */
233 #define RL	0x0800		/* rotate left */
234 #define RR	0x0400		/* rotate right */
235 #define LO	0x8000		/* lookup: ori-{jmp,jc,jnc,call} */
236 #define LA	0x4000		/* lookup: and-{jz,jnz} */
237 #define LX	0x2000		/* lookup: xor-{je,jne} */
238 #define NA	-1		/* not applicable */
239 
240 struct {
241 	char *name;
242 	int n;			/* number of operands, including opcode */
243 	unsigned int op;	/* immediate or L?|pos_from_0 */
244 	unsigned int dest;	/* NA, pos_from_0, or I|immediate */
245 	unsigned int src;	/* NA, pos_from_0, or I|immediate */
246 	unsigned int imm;	/* pos_from_0, A|pos_from_0, or I|immediate */
247 	unsigned int addr;	/* NA or pos_from_0 */
248 	int fmt;		/* instruction format - 1, 2, or 3 */
249 } instr[] = {
250 /*
251  *		N  OP	 DEST		SRC		IMM	ADDR FMT
252  */
253 	"mov",	3, 1,	 1,		2,		I|0xff,	NA,  1,
254 	"mov",	4, LO|2, NA,		1,		I|0,	3,   3,
255 	"mvi",	3, 0,	 1,		I|R_ALLZEROS,	A|2,	NA,  1,
256 	"mvi",	4, LO|2, NA,		I|R_ALLZEROS,	1,	3,   3,
257 	"not",	2, 2,	 1,		1,		I|0xff,	NA,  1,
258 	"not",	3, 2,	 1,		2,		I|0xff,	NA,  1,
259 	"and",	3, 1,	 1,		1,		A|2,	NA,  1,
260 	"and",  4, 1,	 1,		3,		A|2,	NA,  1,
261 	"or",	3, 0,	 1,		1,		A|2,	NA,  1,
262 	"or",	4, 0,	 1,		3,		A|2,	NA,  1,
263 	"or",	5, LO|3, NA,		1,		2,	4,   3,
264 	"xor",	3, 2,	 1,		1,		A|2,	NA,  1,
265 	"xor",	4, 2,	 1,		3,		A|2,	NA,  1,
266 	"nop",	1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,  1,
267 	"inc",	2, 3,	 1,		1,		I|1,	NA,  1,
268 	"inc",	3, 3,	 1,		2,		I|1,	NA,  1,
269 	"dec",	2, 3,	 1,		1,		I|0xff,	NA,  1,
270 	"dec",	3, 3,	 1,		2,		I|0xff,	NA,  1,
271 	"jmp",	2, LO|0, NA,		I|R_SINDEX,	I|0,	1,   3,
272 	"jc",	2, LO|0, NA,		I|R_SINDEX,	I|0,	1,   3,
273 	"jnc",	2, LO|0, NA,		I|R_SINDEX,	I|0,	1,   3,
274 	"call",	2, LO|0, NA,		I|R_SINDEX,	I|0,	1,   3,
275 	"test",	5, LA|3, NA,		1,		A|2,	4,   3,
276 	"cmp",	5, LX|3, NA,		1,		A|2,	4,   3,
277 	"ret",	1, 1,	 I|R_NONE,	I|R_ALLZEROS,	I|0xff,	NA,  1,
278 	"clc",	1, 3,	 I|R_NONE,	I|R_ALLZEROS,	I|1,	NA,  1,
279 	"clc",	4, 3,	 2,		I|R_ALLZEROS,	A|3,	NA,  1,
280 	"stc",	1, 3,	 I|R_NONE,	I|R_ALLONES,	I|1,	NA,  1,
281 	"stc",	2, 3,	 1,		I|R_ALLONES,	I|1,	NA,  1,
282 	"add",	3, 3,	 1,		1,		A|2,	NA,  1,
283 	"add",	4, 3,	 1,		3,		A|2,	NA,  1,
284 	"adc",	3, 4,	 1,		1,		A|2,	NA,  1,
285 	"adc",	4, 4,	 1,		3,		A|2,	NA,  1,
286 	"shl",	3, 5,	 1,		1,		SL|2,	NA,  2,
287 	"shl",	4, 5,	 1,		2,		SL|3,	NA,  2,
288 	"shr",	3, 5,	 1,		1,		SR|2,	NA,  2,
289 	"shr",	4, 5,	 1,		2,		SR|3,	NA,  2,
290 	"rol",	3, 5,	 1,		1,		RL|2,	NA,  2,
291 	"rol",	4, 5,	 1,		2,		RL|3,	NA,  2,
292 	"ror",	3, 5,	 1,		1,		RR|2,	NA,  2,
293 	"ror",	4, 5,	 1,		2,		RR|3,	NA,  2,
294 	/*
295 	 *  Extensions (note also that mvi allows A)
296 	 */
297  	"clr",	2, 1,	 1,		I|R_ALLZEROS,	I|0xff,	NA,  1,
298 	0
299 };
300 
301 int eval_operand(char **a, int spec)
302 {
303 	int i;
304 	unsigned int want = spec & (LO|LA|LX);
305 
306 	static struct {
307 		unsigned int what;
308 		char *name;
309 		int value;
310 	} jmptab[] = {
311 		LO,	"jmp",		8,
312 		LO,	"jc",		9,
313 		LO,	"jnc",		10,
314 		LO,	"call",		11,
315 		LA,	"jz",		15,
316 		LA,	"jnz",		13,
317 		LX,	"je",		14,
318 		LX,	"jne",		12,
319 	};
320 
321 	spec &= ~(LO|LA|LX);
322 
323 	for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
324 		if (jmptab[i].what == want &&
325 		    !strcmp(jmptab[i].name, a[spec]))
326 		{
327 			return(jmptab[i].value);
328 		}
329 
330 	if (want)
331 		error("invalid jump");
332 
333 	return(spec);		/* "case 0" - no flags set */
334 }
335 
336 int eval_sdi(char **a, int spec)
337 {
338 	sym_t *p;
339 	unsigned val;
340 
341 	if (spec == NA)
342 		return(NA);
343 
344 	switch (spec & (A|I|SL|SR|RL|RR)) {
345 	    case SL:
346 	    case SR:
347 	    case RL:
348 	    case RR:
349 		if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
350 			val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
351 		else {
352 			p = lookup(a[spec &~ (SL|SR|RL|RR)]);
353 			if (!p)
354 				error("undefined symbol used");
355 			val = p->value;
356 		}
357 
358 		switch (spec & (SL|SR|RL|RR)) {		/* blech */
359 		    case SL:
360 			if (val > 7)
361 				return(0xf0);
362 			return(((val % 8) << 4) |
363 			       (val % 8));
364 		    case SR:
365 			if (val > 7)
366 				return(0xf0);
367 			return(((val % 8) << 4) |
368 			       (1 << 3) |
369 			       ((8 - (val % 8)) % 8));
370 		    case RL:
371 			return(val % 8);
372 		    case RR:
373 			return((8 - (val % 8)) % 8);
374 		}
375 	    case I:
376 		return(spec &~ I);
377 	    case A:
378 		/*
379 		 *  An immediate field of zero selects
380 		 *  the accumulator.  Vigorously object
381 		 *  if zero is given otherwise - it's
382 		 *  most likely an error.
383 		 */
384 		spec &= ~A;
385 		if (!strcmp("A", a[spec]))
386 			return(0);
387 		if (isdigit(*a[spec]) &&
388 		    strtol(a[spec], NULL, 0) == 0)
389 		{
390 			error("immediate value of zero selects accumulator");
391 		}
392 		/* falls through */
393 	    case 0:
394 		if (isdigit(*a[spec]))
395 			return(strtol(a[spec], NULL, 0));
396 		p = lookup(a[spec]);
397 		if (p)
398 			return(p->value);
399 		error("undefined symbol used");
400 	}
401 
402 	return(NA);		/* shut the compiler up */
403 }
404 
405 int eval_addr(char **a, int spec)
406 {
407 	sym_t *p;
408 
409 	if (spec == NA)
410 		return(NA);
411 	if (isdigit(*a[spec]))
412 		return(strtol(a[spec], NULL, 0));
413 
414 	p = lookup(a[spec]);
415 
416 	if (p) {
417 		if (p->value != NOVALUE)
418 			return(p->value);
419 		patch(p, LC);
420 	} else {
421 		define(a[spec], NOVALUE);
422 		p = lookup(a[spec]);
423 		patch(p, LC);
424 	}
425 
426 	return(NA);		/* will be patched in later */
427 }
428 
429 int crack(char **a, int n)
430 {
431 	int i;
432 	int I_imm, I_addr;
433 	int I_op, I_dest, I_src, I_ret;
434 
435 	/*
436 	 *  Check for "ret" at the end of the line; remove
437 	 *  it unless it's "ret" alone - we still want to
438 	 *  look it up in the table.
439 	 */
440 	I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
441 	if (I_ret && n > 1)
442 		n -= 1;
443 
444 	for (i = 0; instr[i].name; i++) {
445 		/*
446 		 *  Look for match in table given constraints,
447 		 *  currently just the name and the number of
448 		 *  operands.
449 		 */
450 		if (!strcmp(instr[i].name, *a) && instr[i].n == n)
451 			break;
452 	}
453 	if (!instr[i].name)
454 		error("unknown opcode or wrong number of operands");
455 
456 	I_op	= eval_operand(a, instr[i].op);
457 	I_src	= eval_sdi(a, instr[i].src);
458 	I_imm	= eval_sdi(a, instr[i].imm);
459 	I_dest	= eval_sdi(a, instr[i].dest);
460 	I_addr	= eval_addr(a, instr[i].addr);
461 
462 	switch (instr[i].fmt) {
463 	    case 1:
464 	    case 2:
465 		M[LC][0] = (I_op << 1) | I_ret;
466 		M[LC][1] = I_dest;
467 		M[LC][2] = I_src;
468 		M[LC][3] = I_imm;
469 		break;
470 	    case 3:
471 		if (I_ret)
472 			error("illegal use of \"ret\"");
473 		M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
474 		M[LC][1] = I_addr & 0xff;
475 		M[LC][2] = I_src;
476 		M[LC][3] = I_imm;
477 		break;
478 	}
479 
480 	return(1);		/* no two-byte instructions yet */
481 }
482 
483 #undef SL
484 #undef SR
485 #undef RL
486 #undef RR
487 #undef LX
488 #undef LA
489 #undef LO
490 #undef I
491 #undef A
492 
493 void assemble(void)
494 {
495 	int n;
496 	char **a;
497 	sym_t *p;
498 
499 	while ((a = getl(&n))) {
500 
501 		while (a[0][strlen(*a)-1] == ':') {
502 			a[0][strlen(*a)-1] = '\0';
503 			p = lookup(*a);
504 			if (p)
505 				p->value = LC;
506 			else
507 				define(*a, LC);
508 			a += 1;
509 			n -= 1;
510 		}
511 
512 		if (!n)			/* line was all labels */
513 			continue;
514 
515 		if (n == 3 && !strcmp("VERSION", *a))
516 			fprintf(ofp, "#define %s \"%s\"\n", a[1], a[2]);
517 		else {
518 			if (n == 3 && !strcmp("=", a[1]))
519 				define(*a, strtol(a[2], NULL, 0));
520 			else
521 				LC += crack(a, n);
522 		}
523 	}
524 
525 	backpatch();
526 	output(ofp);
527 
528 	if (debug)
529 		output(stderr);
530 }
531 
532 int main(int argc, char **argv)
533 {
534 	int c;
535 
536 	while ((c = getopt(argc, argv, "dho:")) != EOF) {
537 		switch (c) {
538 		    case 'd':
539 			debug = !0;
540 			break;
541 		    case 'o':
542 		        ofp = fopen(optarg, "w");
543 			if (!ofp) {
544 				perror(optarg);
545 				exit(EXIT_FAILURE);
546 			}
547 			break;
548 		    case 'h':
549 			printf("usage: %s [-d] [-ooutput] input\n", *argv);
550 			exit(EXIT_SUCCESS);
551 		    case NULL:
552 			/*
553 			 *  An impossible option to shut the compiler
554 			 *  up about sccsid[].
555 			 */
556 			exit((int)sccsid);
557 		    default:
558 			exit(EXIT_FAILURE);
559 		}
560 	}
561 
562 	if (argc - optind != 1) {
563 		fprintf(stderr, "%s: must have one input file\n", *argv);
564 		exit(EXIT_FAILURE);
565 	}
566 	filename = argv[optind];
567 
568 	ifp = fopen(filename, "r");
569 	if (!ifp) {
570 		perror(filename);
571 		exit(EXIT_FAILURE);
572 	}
573 
574 	if (!ofp) {
575 		ofp = fopen(ADOTOUT, "w");
576 		if (!ofp) {
577 			perror(ADOTOUT);
578 			exit(EXIT_FAILURE);
579 		}
580 	}
581 
582 	assemble();
583 	exit(EXIT_SUCCESS);
584 }
585