This source file includes following definitions.
- error
- Malloc
- Realloc
- Strdup
- define
- lookup
- patch
- backpatch
- output
- getl
- eval_operand
- eval_sdi
- eval_addr
- crack
- assemble
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
40 #define MAXLINE 1024
41 #define MAXTOKEN 32
42 #define ADOTOUT "a.out"
43 #define NOVALUE -1
44
45
46
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;
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
182
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
230 #define I 0x4000
231 #define SL 0x2000
232 #define SR 0x1000
233 #define RL 0x0800
234 #define RR 0x0400
235 #define LO 0x8000
236 #define LA 0x4000
237 #define LX 0x2000
238 #define NA -1
239
240 struct {
241 char *name;
242 int n;
243 unsigned int op;
244 unsigned int dest;
245 unsigned int src;
246 unsigned int imm;
247 unsigned int addr;
248 int fmt;
249 } instr[] = {
250
251
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
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);
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)) {
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
380
381
382
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
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);
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);
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
437
438
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
447
448
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);
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)
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
554
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 }