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