ncr53cxxx.c revision 1.8 1 /* $NetBSD: ncr53cxxx.c,v 1.8 2002/04/17 21:39:14 bouyer Exp $ */
2
3 /*
4 * Copyright (c) 1995,1999 Michael L. Hitch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Michael L. Hitch.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /* ncr53cxxx.c - SCSI SCRIPTS Assembler */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39
40 #ifndef AMIGA
41 #define strcmpi strcasecmp
42 #endif
43
44 #define MAXTOKENS 16
45 #define MAXINST 1024
46 #define MAXSYMBOLS 128
47
48 struct {
49 int type;
50 char *name;
51 } tokens[MAXTOKENS];
52 int ntokens;
53 int tokenix;
54
55 void f_proc (void);
56 void f_pass (void);
57 void f_list (void); /* ENTRY, EXTERNAL label list */
58 void f_define (void); /* ABSOLUTE, RELATIVE label list */
59 void f_move (void);
60 void f_jump (void);
61 void f_call (void);
62 void f_return (void);
63 void f_int (void);
64 void f_select (void);
65 void f_reselect (void);
66 void f_wait (void);
67 void f_disconnect (void);
68 void f_set (void);
69 void f_clear (void);
70 void f_load (void);
71 void f_store (void);
72 void f_nop (void);
73 void f_arch (void);
74
75 struct {
76 char *name;
77 void (*func)(void);
78 } directives[] = {
79 {"PROC", f_proc},
80 {"PASS", f_pass},
81 {"ENTRY", f_list},
82 {"ABSOLUTE", f_define},
83 {"EXTERN", f_list},
84 {"EXTERNAL", f_list},
85 {"RELATIVE", f_define},
86 {"MOVE", f_move},
87 {"JUMP", f_jump},
88 {"CALL", f_call},
89 {"RETURN", f_return},
90 {"INT", f_int},
91 {"SELECT", f_select},
92 {"RESELECT", f_reselect},
93 {"WAIT", f_wait},
94 {"DISCONNECT", f_disconnect},
95 {"SET", f_set},
96 {"CLEAR", f_clear},
97 {"LOAD", f_load},
98 {"STORE", f_store},
99 {"NOP", f_nop},
100 {"ARCH", f_arch},
101 {NULL, NULL}};
102
103 u_int32_t script[MAXINST];
104 int dsps;
105 char *script_name = "SCRIPT";
106 u_int32_t inst0, inst1, inst2;
107 unsigned int ninsts;
108 unsigned int npatches;
109
110 struct patchlist {
111 struct patchlist *next;
112 unsigned offset;
113 } *patches;
114
115 #define S_LABEL 0x0000
116 #define S_ABSOLUTE 0x0001
117 #define S_RELATIVE 0x0002
118 #define S_EXTERNAL 0x0003
119 #define F_DEFINED 0x0001
120 #define F_ENTRY 0x0002
121 struct {
122 short type;
123 short flags;
124 u_int32_t value;
125 struct patchlist *patchlist;
126 char *name;
127 } symbols[MAXSYMBOLS];
128 int nsymbols;
129
130 char *stypes[] = {"Label", "Absolute", "Relative", "External"};
131
132 char *phases[] = {
133 "data_out", "data_in", "cmd", "status",
134 "res4", "res5", "msg_out", "msg_in"
135 };
136
137 struct ncrregs {
138 char *name;
139 int addr[5];
140 };
141 #define ARCH700 1
142 #define ARCH710 2
143 #define ARCH720 3
144 #define ARCH810 4
145 #define ARCH825 5
146
147 struct ncrregs regs[] = {
148 {"scntl0", {0x00, 0x00, 0x00, 0x00, 0x00}},
149 {"scntl1", {0x01, 0x01, 0x01, 0x01, 0x01}},
150 {"sdid", {0x02, 0x02, -1, -1, -1}},
151 {"sien", {0x03, 0x03, -1, -1, -1}},
152 {"scid", {0x04, 0x04, -1, -1, -1}},
153 {"scntl2", { -1, -1, 0x02, 0x02, 0x02}},
154 {"scntl3", { -1, -1, 0x03, 0x03, 0x03}},
155 {"scid", { -1, -1, 0x04, 0x04, 0x04}},
156 {"sxfer", {0x05, 0x05, 0x05, 0x05, 0x05}},
157 {"sodl", {0x06, 0x06, -1, -1, -1}},
158 {"socl", {0x07, 0x07, -1, -1, -1}},
159 {"sdid", { -1, -1, 0x06, 0x06, 0x06}},
160 {"gpreg", { -1, -1, 0x07, 0x07, 0x07}},
161 {"sfbr", {0x08, 0x08, 0x08, 0x08, 0x08}},
162 {"sidl", {0x09, 0x09, -1, -1, -1}},
163 {"sbdl", {0x0a, 0x0a, -1, -1, -1}},
164 {"socl", { -1, -1, 0x09, 0x09, 0x09}},
165 {"ssid", { -1, -1, 0x0a, 0x0a, 0x0a}},
166 {"sbcl", {0x0b, 0x0b, 0x0b, 0x0b, 0x0b}},
167 {"dstat", {0x0c, 0x0c, 0x0c, 0x0c, 0x0c}},
168 {"sstat0", {0x0d, 0x0d, 0x0d, 0x0d, 0x0d}},
169 {"sstat1", {0x0e, 0x0e, 0x0e, 0x0e, 0x0e}},
170 {"sstat2", {0x0f, 0x0f, 0x0f, 0x0f, 0x0f}},
171 {"dsa0", { -1, 0x10, 0x10, 0x10, 0x10}},
172 {"dsa1", { -1, 0x11, 0x11, 0x11, 0x11}},
173 {"dsa2", { -1, 0x12, 0x12, 0x12, 0x12}},
174 {"dsa3", { -1, 0x13, 0x13, 0x13, 0x13}},
175 {"ctest0", {0x14, 0x14, 0x18, 0x18, 0x18}},
176 {"ctest1", {0x15, 0x15, 0x19, 0x19, 0x19}},
177 {"ctest2", {0x16, 0x16, 0x1a, 0x1a, 0x1a}},
178 {"ctest3", {0x17, 0x17, 0x1b, 0x1b, 0x1b}},
179 {"ctest4", {0x18, 0x18, 0x21, 0x21, 0x21}},
180 {"ctest5", {0x19, 0x19, 0x22, 0x22, 0x22}},
181 {"ctest6", {0x1a, 0x1a, 0x23, 0x23, 0x23}},
182 {"ctest7", {0x1b, 0x1b, -1, -1, -1}},
183 {"temp0", {0x1c, 0x1c, 0x1c, 0x1c, 0x1c}},
184 {"temp1", {0x1d, 0x1d, 0x1d, 0x1d, 0x1d}},
185 {"temp2", {0x1e, 0x1e, 0x1e, 0x1e, 0x1e}},
186 {"temp3", {0x1f, 0x1f, 0x1f, 0x1f, 0x1f}},
187 {"dfifo", {0x20, 0x20, 0x20, 0x20, 0x20}},
188 {"istat", {0x21, 0x21, 0x14, 0x14, 0x14}},
189 {"ctest8", { -1, 0x22, -1, -1, -1}},
190 {"lcrc", { -1, 0x23, -1, -1, -1}},
191 {"dbc0", {0x24, 0x24, 0x24, 0x24, 0x24}},
192 {"dbc1", {0x25, 0x25, 0x25, 0x25, 0x25}},
193 {"dbc2", {0x26, 0x26, 0x26, 0x26, 0x26}},
194 {"dcmd", {0x27, 0x27, 0x27, 0x27, 0x27}},
195 {"dnad0", {0x28, 0x28, 0x28, 0x28, 0x28}},
196 {"dnad1", {0x29, 0x29, 0x29, 0x29, 0x29}},
197 {"dnad2", {0x2a, 0x2a, 0x2a, 0x2a, 0x2a}},
198 {"dnad3", {0x2b, 0x2b, 0x2b, 0x2b, 0x2b}},
199 {"dsp0", {0x2c, 0x2c, 0x2c, 0x2c, 0x2c}},
200 {"dsp1", {0x2d, 0x2d, 0x2d, 0x2d, 0x2d}},
201 {"dsp2", {0x2e, 0x2e, 0x2e, 0x2e, 0x2e}},
202 {"dsp3", {0x2f, 0x2f, 0x2f, 0x2f, 0x2f}},
203 {"dsps0", {0x30, 0x30, 0x30, 0x30, 0x30}},
204 {"dsps1", {0x31, 0x31, 0x31, 0x31, 0x31}},
205 {"dsps2", {0x32, 0x32, 0x32, 0x32, 0x32}},
206 {"dsps3", {0x33, 0x33, 0x33, 0x33, 0x33}},
207 {"scratch0", { -1, 0x34, -1, -1, -1}},
208 {"scratch1", { -1, 0x35, -1, -1, -1}},
209 {"scratch2", { -1, 0x36, -1, -1, -1}},
210 {"scratch3", { -1, 0x37, -1, -1, -1}},
211 {"scratcha0", { -1, -1, 0x34, 0x34, 0x34}},
212 {"scratcha1", { -1, -1, 0x35, 0x35, 0x35}},
213 {"scratcha2", { -1, -1, 0x36, 0x36, 0x36}},
214 {"scratcha3", { -1, -1, 0x37, 0x37, 0x37}},
215 {"dmode", {0x34, 0x38, 0x38, 0x38, 0x38}},
216 {"dien", {0x39, 0x39, 0x39, 0x39, 0x39}},
217 {"dwt", {0x3a, 0x3a, 0x3a, -1, -1}},
218 {"sbr", { -1, -1, -1, 0x3a, 0x3a}},
219 {"dcntl", {0x3b, 0x3b, 0x3b, 0x3b, 0x3b}},
220 {"addr0", { -1, 0x3c, 0x3c, 0x3c, 0x3c}},
221 {"addr1", { -1, 0x3d, 0x3d, 0x3d, 0x3d}},
222 {"addr2", { -1, 0x3e, 0x3e, 0x3e, 0x3e}},
223 {"addr3", { -1, 0x3f, 0x3f, 0x3f, 0x3f}},
224 {"sien0", { -1, -1, 0x40, 0x40, 0x40}},
225 {"sien1", { -1, -1, 0x41, 0x41, 0x41}},
226 {"sist0", { -1, -1, 0x42, 0x42, 0x42}},
227 {"sist1", { -1, -1, 0x43, 0x43, 0x43}},
228 {"slpar", { -1, -1, 0x44, 0x44, 0x44}},
229 {"swide", { -1, -1, 0x45, -1, 0x45}},
230 {"macntl", { -1, -1, 0x46, 0x46, 0x46}},
231 {"gpcntl", { -1, -1, 0x47, 0x47, 0x47}},
232 {"stime0", { -1, -1, 0x48, 0x48, 0x48}},
233 {"stime1", { -1, -1, 0x49, 0x49, 0x49}},
234 {"respid0", { -1, -1, 0x4a, 0x4a, 0x4a}},
235 {"respid1", { -1, -1, 0x4b, -1, 0x4b}},
236 {"stest0", { -1, -1, 0x4c, 0x4c, 0x4c}},
237 {"stest1", { -1, -1, 0x4d, 0x4d, 0x4d}},
238 {"stest2", { -1, -1, 0x4e, 0x4e, 0x4e}},
239 {"stest3", { -1, -1, 0x4f, 0x4f, 0x4f}},
240 {"sidl0", { -1, -1, 0x50, 0x50, 0x50}},
241 {"sidl1", { -1, -1, 0x51, -1, 0x51}},
242 {"sodl0", { -1, -1, 0x54, 0x54, 0x54}},
243 {"sodl1", { -1, -1, 0x55, -1, 0x55}},
244 {"sbdl0", { -1, -1, 0x58, 0x58, 0x58}},
245 {"sbdl1", { -1, -1, 0x59, -1, 0x59}},
246 {"scratchb0", { -1, -1, 0x5c, 0x5c, 0x5c}},
247 {"scratchb1", { -1, -1, 0x5d, 0x5d, 0x5d}},
248 {"scratchb2", { -1, -1, 0x5e, 0x5e, 0x5e}},
249 {"scratchb3", { -1, -1, 0x5f, 0x5f, 0x5f}},
250 {"scratchc0", { -1, -1, -1, -1, 0x60}},
251 {"scratchc1", { -1, -1, -1, -1, 0x61}},
252 {"scratchc2", { -1, -1, -1, -1, 0x62}},
253 {"scratchc3", { -1, -1, -1, -1, 0x63}},
254 {"scratchd0", { -1, -1, -1, -1, 0x64}},
255 {"scratchd1", { -1, -1, -1, -1, 0x65}},
256 {"scratchd2", { -1, -1, -1, -1, 0x5e}},
257 {"scratchd3", { -1, -1, -1, -1, 0x67}},
258 {"scratche0", { -1, -1, -1, -1, 0x68}},
259 {"scratche1", { -1, -1, -1, -1, 0x69}},
260 {"scratche2", { -1, -1, -1, -1, 0x6a}},
261 {"scratche3", { -1, -1, -1, -1, 0x6b}},
262 {"scratchf0", { -1, -1, -1, -1, 0x6c}},
263 {"scratchf1", { -1, -1, -1, -1, 0x6d}},
264 {"scratchf2", { -1, -1, -1, -1, 0x6e}},
265 {"scratchf3", { -1, -1, -1, -1, 0x6f}},
266 {"scratchg0", { -1, -1, -1, -1, 0x70}},
267 {"scratchg1", { -1, -1, -1, -1, 0x71}},
268 {"scratchg2", { -1, -1, -1, -1, 0x72}},
269 {"scratchg3", { -1, -1, -1, -1, 0x73}},
270 {"scratchh0", { -1, -1, -1, -1, 0x74}},
271 {"scratchh1", { -1, -1, -1, -1, 0x75}},
272 {"scratchh2", { -1, -1, -1, -1, 0x7e}},
273 {"scratchh3", { -1, -1, -1, -1, 0x77}},
274 {"scratchi0", { -1, -1, -1, -1, 0x78}},
275 {"scratchi1", { -1, -1, -1, -1, 0x79}},
276 {"scratchi2", { -1, -1, -1, -1, 0x7a}},
277 {"scratchi3", { -1, -1, -1, -1, 0x7b}},
278 {"scratchj0", { -1, -1, -1, -1, 0x7c}},
279 {"scratchj1", { -1, -1, -1, -1, 0x7d}},
280 {"scratchj2", { -1, -1, -1, -1, 0x7e}},
281 {"scratchj3", { -1, -1, -1, -1, 0x7f}},
282 };
283
284 int lineno;
285 int err_listed;
286 int arch;
287 int partial_flag;
288
289 char inbuf[128];
290
291 char *sourcefile;
292 char *outputfile;
293 char *listfile;
294 char *errorfile;
295
296 FILE *infp;
297 FILE *outfp;
298 FILE *listfp;
299 FILE *errfp;
300
301 void setarch(char *);
302 void parse (void);
303 void process (void);
304 void emit_symbols (void);
305 void list_symbols (void);
306 void errout (char *);
307 void define_symbol (char *, u_int32_t, short, short);
308 void patch_label (void);
309 void close_script (void);
310 void new_script (char *);
311 void store_inst (void);
312 int expression (int *);
313 int evaluate (int);
314 int number (char *);
315 int lookup (char *);
316 int reserved (char *, int);
317 int CheckPhase (int);
318 int CheckRegister (int);
319 void transfer (int, int);
320 void select_reselect (int);
321 void set_clear (u_int32_t);
322 void block_move (void);
323 void register_write (void);
324 void memory_to_memory (void);
325 void loadstore (int);
326 void error_line(void);
327 char *makefn(char *, char *);
328 void usage(void);
329
330 int
331 main (int argc, char *argv[])
332 {
333 int i;
334 struct patchlist *p;
335
336 if (argc < 2 || argv[1][0] == '-')
337 usage();
338 sourcefile = argv[1];
339 infp = fopen (sourcefile, "r");
340 if (infp == NULL) {
341 perror ("open source");
342 fprintf (stderr, "scc: error opening source file %s\n", argv[1]);
343 exit (1);
344 }
345 /*
346 * process options
347 * -l [listfile]
348 * -o [outputfile]
349 * -p [outputfile]
350 * -z [debugfile]
351 * -e [errorfile]
352 * -a arch
353 * -v
354 * -u
355 */
356 for (i = 2; i < argc; ++i) {
357 if (argv[i][0] != '-')
358 usage();
359 switch (argv[i][1]) {
360 case 'o':
361 case 'p':
362 partial_flag = argv[i][1] == 'p';
363 if (i + 1 >= argc || argv[i + 1][0] == '-')
364 outputfile = makefn (sourcefile, "out");
365 else {
366 outputfile = argv[i + 1];
367 ++i;
368 }
369 break;
370 case 'l':
371 if (i + 1 >= argc || argv[i + 1][0] == '-')
372 listfile = makefn (sourcefile, "lis");
373 else {
374 listfile = argv[i + 1];
375 ++i;
376 }
377 break;
378 case 'e':
379 if (i + 1 >= argc || argv[i + 1][0] == '-')
380 errorfile = makefn (sourcefile, "err");
381 else {
382 errorfile = argv[i + 1];
383 ++i;
384 }
385 break;
386 case 'a':
387 if (i + 1 == argc)
388 usage();
389 setarch(argv[i +1]);
390 if (arch == 0) {
391 fprintf(stderr,"%s: bad arch '%s'\n",
392 argv[0], argv[i +1]);
393 exit(1);
394 }
395 ++i;
396 break;
397 default:
398 fprintf (stderr, "scc: unrecognized option '%c'\n",
399 argv[i][1]);
400 usage();
401 }
402 }
403 if (outputfile)
404 outfp = fopen (outputfile, "w");
405 if (listfile)
406 listfp = fopen (listfile, "w");
407 if (errorfile)
408 errfp = fopen (errorfile, "w");
409 else
410 errfp = stderr;
411
412 if (outfp) {
413 time_t cur_time;
414
415 fprintf(outfp, "/*\t$NetBSD: ncr53cxxx.c,v 1.8 2002/04/17 21:39:14 bouyer Exp $\t*/\n");
416 fprintf(outfp, "/*\n");
417 fprintf(outfp, " *\tDO NOT EDIT - this file is automatically generated.\n");
418 time(&cur_time);
419 fprintf(outfp, " *\tcreated from %s on %s", sourcefile, ctime(&cur_time));
420 fprintf(outfp, " */\n");
421 }
422
423 while (fgets (inbuf, sizeof (inbuf), infp)) {
424 ++lineno;
425 if (listfp)
426 fprintf (listfp, "%3d: %s", lineno, inbuf);
427 err_listed = 0;
428 parse ();
429 if (ntokens) {
430 #ifdef DUMP_TOKENS
431 int i;
432
433 fprintf (listfp, " %d tokens\n", ntokens);
434 for (i = 0; i < ntokens; ++i) {
435 fprintf (listfp, " %d: ", i);
436 if (tokens[i].type)
437 fprintf (listfp,"'%c'\n", tokens[i].type);
438 else
439 fprintf (listfp, "%s\n", tokens[i].name);
440 }
441 #endif
442 if (ntokens >= 2 && tokens[0].type == 0 &&
443 tokens[1].type == ':') {
444 define_symbol (tokens[0].name, dsps, S_LABEL, F_DEFINED);
445 tokenix += 2;
446 }
447 if (tokenix < ntokens)
448 process ();
449 }
450
451 }
452 close_script ();
453 emit_symbols ();
454 if (outfp && !partial_flag) {
455 fprintf (outfp, "\nu_int32_t INSTRUCTIONS = 0x%08x;\n", ninsts);
456 fprintf (outfp, "u_int32_t PATCHES = 0x%08x;\n", npatches);
457 fprintf (outfp, "u_int32_t LABELPATCHES[] = {\n");
458 p = patches;
459 while (p) {
460 fprintf (outfp, "\t0x%08x,\n", p->offset / 4);
461 p = p->next;
462 }
463 fprintf (outfp, "};\n\n");
464 }
465 list_symbols ();
466 exit(0);
467 }
468
469 void setarch(char *val)
470 {
471 switch (atoi(val)) {
472 case 700:
473 arch = ARCH700;
474 break;
475 case 710:
476 arch = ARCH710;
477 break;
478 case 720:
479 arch = ARCH720;
480 break;
481 case 810:
482 arch = ARCH810;
483 break;
484 case 825:
485 arch = ARCH825;
486 break;
487 default:
488 arch = 0;
489 }
490 }
491
492 void emit_symbols ()
493 {
494 int i;
495 struct patchlist *p;
496
497 if (nsymbols == 0 || outfp == NULL)
498 return;
499
500 for (i = 0; i < nsymbols; ++i) {
501 char *code;
502 if ((symbols[i].flags & F_DEFINED) == 0 &&
503 symbols[i].type != S_EXTERNAL) {
504 fprintf(stderr, "warning: symbol %s undefined\n",
505 symbols[i].name);
506 }
507 if (symbols[i].type == S_ABSOLUTE)
508 code = "A_";
509 else if (symbols[i].type == S_RELATIVE)
510 code = "R_";
511 else if (symbols[i].type == S_EXTERNAL)
512 code = "E_";
513 else if (symbols[i].flags & F_ENTRY)
514 code = "Ent_";
515 else
516 continue;
517 fprintf (outfp, "#define\t%s%s\t0x%08x\n", code, symbols[i].name,
518 symbols[i].value);
519 if (symbols[i].flags & F_ENTRY || symbols[i].patchlist == NULL)
520 continue;
521 fprintf (outfp, "u_int32_t %s%s_Used[] = {\n", code, symbols[i].name);
522 #if 1
523 p = symbols[i].patchlist;
524 while (p) {
525 fprintf (outfp, "\t0x%08x,\n", p->offset / 4);
526 p = p->next;
527 }
528 #endif
529 fprintf (outfp, "};\n\n");
530 }
531 /* patches ? */
532 }
533
534 void list_symbols ()
535 {
536 int i;
537
538 if (nsymbols == 0 || listfp == NULL)
539 return;
540 fprintf (listfp, "\n\nValue Type Symbol\n");
541 for (i = 0; i < nsymbols; ++i) {
542 fprintf (listfp, "%08x: %-8s %s\n", symbols[i].value,
543 stypes[symbols[i].type], symbols[i].name);
544 }
545 }
546
547 void errout (char *text)
548 {
549 error_line();
550 fprintf (errfp, "*** %s ***\n", text);
551 }
552
553 void parse ()
554 {
555 char *p = inbuf;
556 char c;
557 char string[64];
558 char *s;
559
560 ntokens = tokenix = 0;
561 while (1) {
562 while ((c = *p++) && c != '\n' && (c <= ' ' || c == '\t'))
563 ;
564 if (c == '\n' || c == 0 || c == ';')
565 break;
566 if (ntokens >= MAXTOKENS) {
567 errout ("Token table full");
568 break;
569 }
570 if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
571 (c >= 'A' && c <= 'Z') || c == '$' || c == '_') {
572 s = string;
573 *s++ = c;
574 while (((c = *p) >= '0' && c <= '9') ||
575 (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
576 c == '_' || c == '$') {
577 *s++ = *p++;
578 }
579 *s = 0;
580 tokens[ntokens].name = malloc (strlen (string) + 1);
581 strcpy (tokens[ntokens].name, string);
582 tokens[ntokens].type = 0;
583 }
584 else {
585 tokens[ntokens].type = c;
586 }
587 ++ntokens;
588 }
589 return;
590 }
591
592 void process ()
593 {
594 int i;
595
596 if (tokens[tokenix].type) {
597 error_line();
598 fprintf (errfp, "Error: expected directive, found '%c'\n",
599 tokens[tokenix].type);
600 return;
601 }
602 for (i = 0; directives[i].name; ++i) {
603 if (strcmpi (directives[i].name, tokens[tokenix].name) == 0)
604 break;
605 }
606 if (directives[i].name == NULL) {
607 error_line();
608 fprintf (errfp, "Error: expected directive, found \"%s\"\n",
609 tokens[tokenix].name);
610 return;
611 }
612 if (directives[i].func == NULL) {
613 error_line();
614 fprintf (errfp, "No function for directive \"%s\"\n", tokens[tokenix].name);
615 } else {
616 #if 0
617 fprintf (listfp, "Processing directive \"%s\"\n", directives[i].name);
618 #endif
619 ++tokenix;
620 (*directives[i].func) ();
621 }
622 }
623
624 void define_symbol (char *name, u_int32_t value, short type, short flags)
625 {
626 int i;
627 struct patchlist *p;
628
629 for (i = 0; i < nsymbols; ++i) {
630 if (symbols[i].type == type && strcmp (symbols[i].name, name) == 0) {
631 if (symbols[i].flags & F_DEFINED) {
632 error_line();
633 fprintf (errfp, "*** Symbol \"%s\" multiply defined\n",
634 name);
635 } else {
636 symbols[i].flags |= flags;
637 symbols[i].value = value;
638 p = symbols[i].patchlist;
639 while (p) {
640 if (p->offset > dsps)
641 errout ("Whoops\007");
642 else
643 script[p->offset / 4] += dsps;
644 p = p->next;
645 }
646 }
647 return;
648 }
649 }
650 if (nsymbols >= MAXSYMBOLS) {
651 errout ("Symbol table full");
652 return;
653 }
654 symbols[nsymbols].type = type;
655 symbols[nsymbols].flags = flags;
656 symbols[nsymbols].value = value;
657 symbols[nsymbols].patchlist = NULL;
658 symbols[nsymbols].name = malloc (strlen (name) + 1);
659 strcpy (symbols[nsymbols].name, name);
660 ++nsymbols;
661 }
662
663 void patch_label (void)
664 {
665 struct patchlist *p, **h;
666
667 h = &patches;
668 while(*h)
669 h = &(*h)->next;
670 p = (struct patchlist *) malloc (sizeof (struct patchlist));
671 *h = p;
672 p->next = NULL;
673 p->offset = dsps + 4;
674 npatches++;
675 }
676
677 void close_script ()
678 {
679 int i;
680
681 if (dsps == 0)
682 return;
683 if (outfp) {
684 fprintf (outfp, "const u_int32_t %s[] = {\n", script_name);
685 for (i = 0; i < dsps / 4; i += 2) {
686 fprintf (outfp, "\t0x%08x, 0x%08x", script[i],
687 script[i + 1]);
688 /* check for memory move instruction */
689 if ((script[i] & 0xe0000000) == 0xc0000000)
690 fprintf (outfp, ", 0x%08x,", script[i + 2]);
691 else
692 if ((i + 2) <= dsps / 4) fprintf (outfp, ",\t\t");
693 fprintf (outfp, "\t/* %03x - %3d */\n", i * 4, i * 4);
694 if ((script[i] & 0xe0000000) == 0xc0000000)
695 ++i;
696 }
697 fprintf (outfp, "};\n\n");
698 }
699 dsps = 0;
700 }
701
702 void new_script (char *name)
703 {
704 close_script ();
705 script_name = malloc (strlen (name) + 1);
706 strcpy (script_name, name);
707 }
708
709 int reserved (char *string, int t)
710 {
711 if (tokens[t].type == 0 && strcmpi (tokens[t].name, string) == 0)
712 return (1);
713 return (0);
714 }
715
716 int CheckPhase (int t)
717 {
718 int i;
719
720 for (i = 0; i < 8; ++i) {
721 if (reserved (phases[i], t)) {
722 inst0 |= i << 24;
723 return (1);
724 }
725 }
726 return (0);
727 }
728
729 int CheckRegister (int t)
730 {
731 int i;
732
733 if (arch <= 0) {
734 errout("'ARCH' statement missing");
735 return -1;
736 }
737 for (i = 0; i < (sizeof(regs) / sizeof(regs[0])); i++) {
738 if (regs[i].addr[arch - 1] >= 0 && reserved(regs[i].name, t))
739 return regs[i].addr[arch-1];
740 }
741 return (-1);
742 }
743
744 int expression (int *t)
745 {
746 int value;
747 int i = *t;
748
749 value = evaluate (i++);
750 while (i < ntokens) {
751 if (tokens[i].type == '+')
752 value += evaluate (i + 1);
753 else if (tokens[i].type == '-')
754 value -= evaluate (i + 1);
755 else
756 errout ("Unknown identifier");
757 i += 2;
758 }
759 *t = i;
760 return (value);
761 }
762
763 int evaluate (t)
764 {
765 int value;
766 char *name;
767
768 if (tokens[t].type) {
769 errout ("Expected an identifier");
770 return (0);
771 }
772 name = tokens[t].name;
773 if (*name >= '0' && *name <= '9')
774 value = number (name);
775 else
776 value = lookup (name);
777 return (value);
778 }
779
780 int number (char *s)
781 {
782 int value;
783 int n;
784 int radix;
785
786 radix = 10;
787 if (*s == '0') {
788 ++s;
789 radix = 8;
790 switch (*s) {
791 case 'x':
792 case 'X':
793 radix = 16;
794 break;
795 case 'b':
796 case 'B':
797 radix = 2;
798 }
799 if (radix != 8)
800 ++s;
801 }
802 value = 0;
803 while (*s) {
804 n = *s++;
805 if (n >= '0' && n <= '9')
806 n -= '0';
807 else if (n >= 'a' && n <= 'f')
808 n -= 'a' - 10;
809 else if (n >= 'A' && n <= 'F')
810 n -= 'A' - 10;
811 else {
812 error_line();
813 fprintf (errfp, "*** Expected digit\n");
814 n = 0;
815 }
816 if (n >= radix)
817 errout ("Expected digit");
818 else
819 value = value * radix + n;
820 }
821 return (value);
822 }
823
824 int lookup (char *name)
825 {
826 int i;
827 struct patchlist *p;
828
829 for (i = 0; i < nsymbols; ++i) {
830 if (strcmp (name, symbols[i].name) == 0) {
831 if ((symbols[i].flags & F_DEFINED) == 0) {
832 p = (struct patchlist *) &symbols[i].patchlist;
833 while (p->next)
834 p = p->next;
835 p->next = (struct patchlist *) malloc (sizeof (struct patchlist));
836 p = p->next;
837 p->next = NULL;
838 p->offset = dsps + 4;
839 }
840 return ((int) symbols[i].value);
841 }
842 }
843 if (nsymbols >= MAXSYMBOLS) {
844 errout ("Symbol table full");
845 return (0);
846 }
847 symbols[nsymbols].type = S_LABEL; /* assume forward reference */
848 symbols[nsymbols].flags = 0;
849 symbols[nsymbols].value = 0;
850 p = (struct patchlist *) malloc (sizeof (struct patchlist));
851 symbols[nsymbols].patchlist = p;
852 p->next = NULL;
853 p->offset = dsps + 4;
854 symbols[nsymbols].name = malloc (strlen (name) + 1);
855 strcpy (symbols[nsymbols].name, name);
856 ++nsymbols;
857 return (0);
858 }
859
860 void f_arch (void)
861 {
862 int i, archsave;
863
864 i = tokenix;
865
866 archsave = arch;
867 setarch(tokens[i].name);
868 if( arch == 0) {
869 errout("Unrecognized ARCH");
870 arch = archsave;
871 }
872 }
873
874 void f_proc (void)
875 {
876 if (tokens[tokenix].type != 0 || tokens[tokenix + 1].type != ':')
877 errout ("Invalid PROC statement");
878 else
879 new_script (tokens[tokenix].name);
880 }
881
882 void f_pass (void)
883 {
884 errout ("PASS option not implemented");
885 }
886
887 /*
888 * f_list: process list of symbols for the ENTRY and EXTERNAL directive
889 */
890
891 void f_list (void)
892 {
893 int i;
894 short type;
895 short flags;
896
897 type = strcmpi (tokens[tokenix-1].name, "ENTRY") ? S_EXTERNAL : S_LABEL;
898 flags = type == S_LABEL ? F_ENTRY : 0;
899 for (i = tokenix; i < ntokens; ++i) {
900 if (tokens[i].type != 0) {
901 errout ("Expected an identifier");
902 return;
903 }
904 define_symbol (tokens[i].name, 0, type, flags);
905 if (i + 1 < ntokens) {
906 if (tokens[++i].type == ',')
907 continue;
908 errout ("Expected a separator");
909 return;
910 }
911 }
912 }
913
914 /*
915 * f_define: process list of definitions for ABSOLUTE and RELATIVE directive
916 */
917
918 void f_define (void)
919 {
920 int i;
921 char *name;
922 u_int32_t value;
923 int type;
924
925 type = strcmpi (tokens[tokenix-1].name, "ABSOLUTE") ? S_RELATIVE : S_ABSOLUTE;
926 i = tokenix;
927 while (i < ntokens) {
928 if (tokens[i].type) {
929 errout ("Expected an identifier");
930 return;
931 }
932 if (tokens[i + 1].type != '=') {
933 errout ("Expected a separator");
934 return;
935 }
936 name = tokens[i].name;
937 i += 2;
938 value = expression (&i);
939 define_symbol (name, value, type, F_DEFINED);
940 }
941 }
942
943 void store_inst ()
944 {
945 int i = dsps / 4;
946 int l = 8;
947
948 if ((inst0 & 0xe0000000) == 0xc0000000)
949 l = 12; /* Memory to memory move is 12 bytes */
950 if ((dsps + l) / 4 > MAXINST) {
951 errout ("Instruction table overflow");
952 return;
953 }
954 script[i++] = inst0;
955 script[i++] = inst1;
956 if (l == 12)
957 script[i++] = inst2;
958 if (listfp) {
959 fprintf (listfp, "\t%04x: %08x %08x", dsps, inst0, inst1);
960 if (l == 12)
961 fprintf (listfp, " %08x", inst2);
962 fprintf (listfp, "\n");
963 }
964 dsps += l;
965 inst0 = inst1 = inst2 = 0;
966 ++ninsts;
967 }
968
969 void f_move (void)
970 {
971 if (reserved ("memory", tokenix))
972 memory_to_memory ();
973 else if (reserved ("from", tokenix) || tokens[tokenix+1].type == ',')
974 block_move ();
975 else
976 register_write ();
977 store_inst ();
978 }
979
980 void f_jump (void)
981 {
982 transfer (0x80000000, 0);
983 }
984
985 void f_call (void)
986 {
987 transfer (0x88000000, 0);
988 }
989
990 void f_return (void)
991 {
992 transfer (0x90000000, 1);
993 }
994
995 void f_int (void)
996 {
997 transfer (0x98000000, 2);
998 }
999
1000 void f_select (void)
1001 {
1002 int t = tokenix;
1003
1004 if (reserved ("atn", t)) {
1005 inst0 = 0x01000000;
1006 ++t;
1007 }
1008 select_reselect (t);
1009 }
1010
1011 void f_reselect (void)
1012 {
1013 select_reselect (tokenix);
1014 }
1015
1016 void f_wait (void)
1017 {
1018 int i = tokenix;
1019
1020 inst1 = 0;
1021 if (reserved ("disconnect", i)) {
1022 inst0 = 0x48000000;
1023 }
1024 else {
1025 if (reserved ("reselect", i))
1026 inst0 = 0x50000000;
1027 else if (reserved ("select", i))
1028 inst0 = 0x50000000;
1029 else
1030 errout ("Expected SELECT or RESELECT");
1031 ++i;
1032 if (reserved ("rel", i)) {
1033 if (arch < ARCH710) {
1034 errout ("Wrong arch for relative dsps");
1035 return;
1036 }
1037 i += 2;
1038 inst1 = evaluate (i) - dsps - 8;
1039 inst0 |= 0x04000000;
1040 }
1041 else {
1042 inst1 = evaluate (i);
1043 patch_label();
1044 }
1045 }
1046 store_inst ();
1047 }
1048
1049 void f_disconnect (void)
1050 {
1051 inst0 = 0x48000000;
1052 store_inst ();
1053 }
1054
1055 void f_set (void)
1056 {
1057 set_clear (0x58000000);
1058 }
1059
1060 void f_clear (void)
1061 {
1062 set_clear (0x60000000);
1063 }
1064
1065 void f_load (void)
1066 {
1067 inst0 = 0xe1000000;
1068 if (arch < ARCH810) {
1069 errout ("Wrong arch for load/store");
1070 return;
1071 }
1072 loadstore(tokenix);
1073 }
1074
1075 void f_store (void)
1076 {
1077 int i;
1078 inst0 = 0xe0000000;
1079 if (arch < ARCH810) {
1080 errout ("Wrong arch for load/store");
1081 return;
1082 }
1083 i = tokenix;
1084 if (reserved("noflush", i)) {
1085 inst0 |= 0x2000000;
1086 i++;
1087 }
1088 loadstore(i);
1089 }
1090
1091 void f_nop (void)
1092 {
1093 inst0 = 0x80000000;
1094 inst1 = 0x00000000;
1095 store_inst ();
1096 }
1097
1098 void loadstore(int i)
1099 {
1100 int reg, size;
1101
1102 reg = CheckRegister(i);
1103 if (reg < 0)
1104 errout ("Expected register");
1105 else
1106 inst0 |= reg << 16;
1107 if (reg == 8)
1108 errout ("Register can't be SFBR");
1109 i++;
1110 if (tokens[i].type == ',')
1111 i++;
1112 else
1113 errout ("expected ','");
1114 size = evaluate(i);
1115 if (i < 1 || i > 4)
1116 errout("wrong size");
1117 if ((reg & 0x3) + size > 4)
1118 errout("size too big for register");
1119 inst0 |= size;
1120 i++;
1121 if (tokens[i].type == ',')
1122 i++;
1123 else
1124 errout ("expected ','");
1125 if (reserved("from", i) || reserved("dsarel", i)) {
1126 if (arch < ARCH710) {
1127 errout ("Wrong arch for table indirect");
1128 return;
1129 }
1130 i++;
1131 inst0 |= 0x10000000;
1132 }
1133 inst1 = evaluate(i);
1134 store_inst ();
1135 }
1136
1137 void transfer (int word0, int type)
1138 {
1139 int i;
1140
1141 i = tokenix;
1142 inst0 = word0;
1143 if (type == 0 && reserved ("rel", i)) {
1144 if (arch < ARCH710) {
1145 errout ("Wrong arch for relative dsps");
1146 return;
1147 }
1148 inst1 = evaluate (i + 2) - dsps - 8;
1149 i += 4;
1150 inst0 |= 0x00800000;
1151 }
1152 else if (type != 1) {
1153 inst1 = evaluate (i);
1154 ++i;
1155 if (type == 0)
1156 patch_label();
1157 }
1158 if (i >= ntokens) {
1159 inst0 |= 0x00080000;
1160 store_inst ();
1161 return;
1162 }
1163 if (tokens[i].type != ',')
1164 errout ("Expected a separator, ',' assumed");
1165 else
1166 ++i;
1167 if (reserved("when", i))
1168 inst0 |= 0x00010000;
1169 else if (reserved ("if", i) == 0) {
1170 errout ("Expected a reserved word");
1171 store_inst ();
1172 return;
1173 }
1174 i++;
1175 if (reserved("false", i)) {
1176 store_inst ();
1177 return;
1178 }
1179 if (reserved ("not", i))
1180 ++i;
1181 else
1182 inst0 |= 0x00080000;
1183 if (reserved ("atn", i)) {
1184 inst0 |= 0x00020000;
1185 ++i;
1186 } else if (CheckPhase (i)) {
1187 inst0 |= 0x00020000;
1188 ++i;
1189 }
1190 if (i < ntokens && tokens[i].type != ',') {
1191 if (inst0 & 0x00020000) {
1192 if (inst0 & 0x00080000 && reserved ("and", i)) {
1193 ++i;
1194 }
1195 else if ((inst0 & 0x00080000) == 0 && reserved ("or", i)) {
1196 ++i;
1197 }
1198 else
1199 errout ("Expected a reserved word");
1200 }
1201 inst0 |= 0x00040000 + (evaluate (i++) & 0xff);
1202 }
1203 if (i < ntokens) {
1204 if (tokens[i].type == ',')
1205 ++i;
1206 else
1207 errout ("Expected a separator, ',' assumed");
1208 if (reserved ("and", i) && reserved ("mask", i + 1))
1209 inst0 |= ((evaluate (i + 2) & 0xff) << 8);
1210 else
1211 errout ("Expected , AND MASK");
1212 }
1213 store_inst ();
1214 }
1215
1216 void select_reselect (int t)
1217 {
1218 inst0 |= 0x40000000; /* ATN may be set from SELECT */
1219 if (reserved ("from", t)) {
1220 if (arch < ARCH710) {
1221 errout ("Wrong arch for table indirect");
1222 return;
1223 }
1224 ++t;
1225 inst0 |= 0x02000000 | evaluate (t++);
1226 }
1227 else
1228 inst0 |= (evaluate (t++) & 0xff) << 16;
1229 if (tokens[t++].type == ',') {
1230 if (reserved ("rel", t)) {
1231 if (arch < ARCH710) {
1232 errout ("Wrong arch for relative dsps");
1233 return;
1234 }
1235 inst0 |= 0x04000000;
1236 inst1 = evaluate (t + 2) - dsps - 8;
1237 }
1238 else {
1239 inst1 = evaluate (t);
1240 patch_label();
1241 }
1242 }
1243 else
1244 errout ("Expected separator");
1245 store_inst ();
1246 }
1247
1248 void set_clear (u_int32_t code)
1249 {
1250 int i = tokenix;
1251 short need_and = 0;
1252
1253 inst0 = code;
1254 while (i < ntokens) {
1255 if (need_and) {
1256 if (reserved ("and", i))
1257 ++i;
1258 else
1259 errout ("Expected AND");
1260 }
1261 if (reserved ("atn", i)) {
1262 inst0 |= 0x0008;
1263 ++i;
1264 }
1265 else if (reserved ("ack", i)) {
1266 inst0 |= 0x0040;
1267 ++i;
1268 }
1269 else if (reserved ("target", i)) {
1270 inst0 |= 0x0200;
1271 ++i;
1272 }
1273 else
1274 errout ("Expected ATN, ACK, or TARGET");
1275 need_and = 1;
1276 }
1277 store_inst ();
1278 }
1279
1280 void block_move ()
1281 {
1282 if (reserved ("from", tokenix)) {
1283 if (arch < ARCH710) {
1284 errout ("Wrong arch for table indirect");
1285 return;
1286 }
1287 inst1 = evaluate (tokenix+1);
1288 inst0 |= 0x10000000 | inst1; /*** ??? to match Zeus script */
1289 tokenix += 2;
1290 }
1291 else {
1292 inst0 |= evaluate (tokenix++); /* count */
1293 tokenix++; /* skip ',' */
1294 if (reserved ("ptr", tokenix)) {
1295 ++ tokenix;
1296 inst0 |= 0x20000000;
1297 }
1298 inst1 = evaluate (tokenix++); /* address */
1299 }
1300 if (tokens[tokenix].type != ',')
1301 errout ("Expected separator");
1302 if (reserved ("when", tokenix + 1)) {
1303 inst0 |= 0x08000000;
1304 CheckPhase (tokenix + 2);
1305 }
1306 else if (reserved ("with", tokenix + 1)) {
1307 CheckPhase (tokenix + 2);
1308 }
1309 else
1310 errout ("Expected WITH or WHEN");
1311 }
1312
1313 void register_write ()
1314 {
1315 /*
1316 * MOVE reg/data8 TO reg register write
1317 * MOVE reg <op> data8 TO reg register write
1318 * MOVE reg + data8 TO reg WITH CARRY register write
1319 */
1320 int op;
1321 int reg;
1322 int data;
1323
1324 if (reserved ("to", tokenix+1))
1325 op = 0;
1326 else if (tokens[tokenix+1].type == '|')
1327 op = 2;
1328 else if (tokens[tokenix+1].type == '&')
1329 op = 4;
1330 else if (tokens[tokenix+1].type == '+')
1331 op = 6;
1332 else if (tokens[tokenix+1].type == '-')
1333 op = 8;
1334 else
1335 errout ("Unknown register operator");
1336 if (op && reserved ("to", tokenix+3) == 0)
1337 errout ("Register command expected TO");
1338 reg = CheckRegister (tokenix);
1339 if (reg < 0) { /* Not register, must be data */
1340 data = evaluate (tokenix);
1341 if (op)
1342 errout ("Register operator not move");
1343 reg = CheckRegister (tokenix+2);
1344 if (reg < 0)
1345 errout ("Expected register");
1346 inst0 = 0x78000000 | (data << 8) | reg << 16;
1347 #if 0
1348 fprintf (listfp, "Move data to register: %02x %d\n", data, reg);
1349 #endif
1350 }
1351 else if (op) { /* A register read/write operator */
1352 data = evaluate (tokenix+2);
1353 if (tokenix+5 < ntokens) {
1354 if (!reserved("with", tokenix+5) ||
1355 !reserved("carry", tokenix+6)) {
1356 errout("Expected 'WITH CARRY'");
1357 } else if (op != 6) {
1358 errout("'WITH CARRY' only valide with '+'");
1359 }
1360 op = 7;
1361 }
1362 if (op == 8) {
1363 data = -data;
1364 op = 6;
1365 }
1366 inst0 = (data & 0xff) << 8;
1367 data = CheckRegister (tokenix+4);
1368 if (data < 0)
1369 errout ("Expected register");
1370 if (reg != data && reg != 8 && data != 8)
1371 errout ("One register MUST be SBFR");
1372 if (reg == data) { /* A register read/modify/write */
1373 #if 0
1374 fprintf (listfp, "Read/modify register: %02x %d %d\n", inst0 >> 8, op, reg);
1375 #endif
1376 inst0 |= 0x78000000 | (op << 24) | (reg << 16);
1377 }
1378 else { /* A move to/from SFBR */
1379 if (reg == 8) { /* MOVE SFBR <> TO reg */
1380 #if 0
1381 fprintf (listfp, "Move SFBR to register: %02x %d %d\n", inst0 >> 8, op, data);
1382 #endif
1383 inst0 |= 0x68000000 | (op << 24) | (data << 16);
1384 }
1385 else {
1386 #if 0
1387 fprintf (listfp, "Move register to SFBR: %02x %d %d\n", inst0 >> 8, op, reg);
1388 #endif
1389 inst0 |= 0x70000000 | (op << 24) | (reg << 16);
1390 }
1391 }
1392 }
1393 else { /* register to register */
1394 data = CheckRegister (tokenix+2);
1395 if (data < 0)
1396 errout ("Expected register");
1397 if (reg == 8) /* move SFBR to reg */
1398 inst0 = 0x6a000000 | (data << 16);
1399 else if (data == 8) /* move reg to SFBR */
1400 inst0 = 0x72000000 | (reg << 16);
1401 else
1402 errout ("One register must be SFBR");
1403 }
1404 }
1405
1406 void memory_to_memory ()
1407 {
1408 inst0 = 0xc0000000 + evaluate (tokenix+1);
1409 inst1 = evaluate (tokenix+3);
1410 /*
1411 * need to hack dsps, otherwise patch offset will be wrong for
1412 * second pointer
1413 */
1414 dsps += 4;
1415 inst2 = evaluate (tokenix+5);
1416 dsps -= 4;
1417 }
1418
1419 void error_line()
1420 {
1421 if (errfp != listfp && errfp && err_listed == 0) {
1422 fprintf (errfp, "%3d: %s", lineno, inbuf);
1423 err_listed = 1;
1424 }
1425 }
1426
1427 char * makefn (base, sub)
1428 char *base;
1429 char *sub;
1430 {
1431 char *fn;
1432
1433 fn = malloc (strlen (base) + strlen (sub) + 2);
1434 strcpy (fn, base);
1435 base = strrchr(fn, '.');
1436 if (base)
1437 *base = 0;
1438 strcat (fn, ".");
1439 strcat (fn, sub);
1440 return (fn);
1441 }
1442
1443 void usage()
1444 {
1445 fprintf (stderr, "usage: scc sourcfile [options]\n");
1446 exit(1);
1447 }
1448