xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm_gram.y (revision 1e413cf93298b5b97441a21d9a50fdcd0ee9945e)
1 %{
2 /*-
3  * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
4  *
5  * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
6  * Copyright (c) 2001, 2002 Adaptec Inc.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions, and the following disclaimer,
14  *    without modification.
15  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16  *    substantially similar to the "NO WARRANTY" disclaimer below
17  *    ("Disclaimer") and any redistribution must be conditioned upon
18  *    including a substantially similar Disclaimer requirement for further
19  *    binary redistribution.
20  * 3. Neither the names of the above-listed copyright holders nor the names
21  *    of any contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * Alternatively, this software may be distributed under the terms of the
25  * GNU General Public License ("GPL") version 2 as published by the Free
26  * Software Foundation.
27  *
28  * NO WARRANTY
29  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
32  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
38  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39  * POSSIBILITY OF SUCH DAMAGES.
40  *
41  * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#29 $
42  *
43  * $FreeBSD$
44  */
45 
46 #include <sys/types.h>
47 
48 #include <inttypes.h>
49 #include <regex.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <sysexits.h>
54 
55 #ifdef __linux__
56 #include "../queue.h"
57 #else
58 #include <sys/queue.h>
59 #endif
60 
61 #include "aicasm.h"
62 #include "aicasm_symbol.h"
63 #include "aicasm_insformat.h"
64 
65 int yylineno;
66 char *yyfilename;
67 char stock_prefix[] = "aic_";
68 char *prefix = stock_prefix;
69 char *patch_arg_list;
70 char *versions;
71 static char errbuf[255];
72 static char regex_pattern[255];
73 static symbol_t *cur_symbol;
74 static symbol_t *field_symbol;
75 static symbol_t *scb_or_sram_symbol;
76 static symtype cur_symtype;
77 static symbol_ref_t accumulator;
78 static symbol_ref_t mode_ptr;
79 static symbol_ref_t allones;
80 static symbol_ref_t allzeros;
81 static symbol_ref_t none;
82 static symbol_ref_t sindex;
83 static int instruction_ptr;
84 static int num_srams;
85 static int sram_or_scb_offset;
86 static int download_constant_count;
87 static int in_critical_section;
88 static u_int enum_increment;
89 static u_int enum_next_value;
90 
91 static void process_field(int field_type, symbol_t *sym, int mask);
92 static void initialize_symbol(symbol_t *symbol);
93 static void add_macro_arg(const char *argtext, int position);
94 static void add_macro_body(const char *bodytext);
95 static void process_register(symbol_t **p_symbol);
96 static void format_1_instr(int opcode, symbol_ref_t *dest,
97 			   expression_t *immed, symbol_ref_t *src, int ret);
98 static void format_2_instr(int opcode, symbol_ref_t *dest,
99 			   expression_t *places, symbol_ref_t *src, int ret);
100 static void format_3_instr(int opcode, symbol_ref_t *src,
101 			   expression_t *immed, symbol_ref_t *address);
102 static void test_readable_symbol(symbol_t *symbol);
103 static void test_writable_symbol(symbol_t *symbol);
104 static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
105 static void make_expression(expression_t *immed, int value);
106 static void add_conditional(symbol_t *symbol);
107 static void add_version(const char *verstring);
108 static int  is_download_const(expression_t *immed);
109 
110 #define SRAM_SYMNAME "SRAM_BASE"
111 #define SCB_SYMNAME "SCB_BASE"
112 %}
113 
114 %union {
115 	u_int		value;
116 	char		*str;
117 	symbol_t	*sym;
118 	symbol_ref_t	sym_ref;
119 	expression_t	expression;
120 }
121 
122 %token T_REGISTER
123 
124 %token <value> T_CONST
125 
126 %token T_EXPORT
127 
128 %token T_DOWNLOAD
129 
130 %token T_SCB
131 
132 %token T_SRAM
133 
134 %token T_ALIAS
135 
136 %token T_SIZE
137 
138 %token T_EXPR_LSHIFT
139 
140 %token T_EXPR_RSHIFT
141 
142 %token <value> T_ADDRESS
143 
144 %token T_ACCESS_MODE
145 
146 %token T_MODES
147 
148 %token T_DEFINE
149 
150 %token T_SET_SRC_MODE
151 
152 %token T_SET_DST_MODE
153 
154 %token <value> T_MODE
155 
156 %token T_BEGIN_CS
157 
158 %token T_END_CS
159 
160 %token T_FIELD
161 
162 %token T_ENUM
163 
164 %token T_MASK
165 
166 %token <value> T_NUMBER
167 
168 %token <str> T_PATH T_STRING T_ARG T_MACROBODY
169 
170 %token <sym> T_CEXPR
171 
172 %token T_EOF T_INCLUDE T_VERSION T_PREFIX T_PATCH_ARG_LIST
173 
174 %token <value> T_SHR T_SHL T_ROR T_ROL
175 
176 %token <value> T_MVI T_MOV T_CLR T_BMOV
177 
178 %token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
179 
180 %token <value> T_ADD T_ADC
181 
182 %token <value> T_INC T_DEC
183 
184 %token <value> T_STC T_CLC
185 
186 %token <value> T_CMP T_NOT T_XOR
187 
188 %token <value> T_TEST T_AND
189 
190 %token <value> T_OR
191 
192 %token T_RET
193 
194 %token T_NOP
195 
196 %token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR
197 
198 %token T_A
199 
200 %token <sym> T_SYMBOL
201 
202 %token T_NL
203 
204 %token T_IF T_ELSE T_ELSE_IF T_ENDIF
205 
206 %type <sym_ref> reg_symbol address destination source opt_source
207 
208 %type <expression> expression immediate immediate_or_a
209 
210 %type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
211 
212 %type <value> mode_value mode_list macro_arglist
213 
214 %left '|'
215 %left '&'
216 %left T_EXPR_LSHIFT T_EXPR_RSHIFT
217 %left '+' '-'
218 %left '*' '/'
219 %right '~'
220 %nonassoc UMINUS
221 %%
222 
223 program:
224 	include
225 |	program include
226 |	prefix
227 |	program prefix
228 |	patch_arg_list
229 |	program patch_arg_list
230 |	version
231 |	program version
232 |	register
233 |	program register
234 |	constant
235 |	program constant
236 |	macrodefn
237 |	program macrodefn
238 |	scratch_ram
239 |	program scratch_ram
240 |	scb
241 |	program scb
242 |	label
243 |	program label
244 |	set_src_mode
245 |	program set_src_mode
246 |	set_dst_mode
247 |	program set_dst_mode
248 |	critical_section_start
249 |	program critical_section_start
250 |	critical_section_end
251 |	program critical_section_end
252 |	conditional
253 |	program conditional
254 |	code
255 |	program code
256 ;
257 
258 include:
259 	T_INCLUDE '<' T_PATH '>'
260 	{
261 		include_file($3, BRACKETED_INCLUDE);
262 	}
263 |	T_INCLUDE '"' T_PATH '"'
264 	{
265 		include_file($3, QUOTED_INCLUDE);
266 	}
267 ;
268 
269 prefix:
270 	T_PREFIX '=' T_STRING
271 	{
272 		if (prefix != stock_prefix)
273 			stop("Prefix multiply defined",
274 			     EX_DATAERR);
275 		prefix = strdup($3);
276 		if (prefix == NULL)
277 			stop("Unable to record prefix", EX_SOFTWARE);
278 	}
279 ;
280 
281 patch_arg_list:
282 	T_PATCH_ARG_LIST '=' T_STRING
283 	{
284 		if (patch_arg_list != NULL)
285 			stop("Patch argument list multiply defined",
286 			     EX_DATAERR);
287 		patch_arg_list = strdup($3);
288 		if (patch_arg_list == NULL)
289 			stop("Unable to record patch arg list", EX_SOFTWARE);
290 	}
291 ;
292 
293 version:
294 	T_VERSION '=' T_STRING
295 	{ add_version($3); }
296 ;
297 
298 register:
299 	T_REGISTER { cur_symtype = REGISTER; } reg_definition
300 ;
301 
302 reg_definition:
303 	T_SYMBOL '{'
304 		{
305 			if ($1->type != UNINITIALIZED) {
306 				stop("Register multiply defined", EX_DATAERR);
307 				/* NOTREACHED */
308 			}
309 			cur_symbol = $1;
310 			cur_symbol->type = cur_symtype;
311 			initialize_symbol(cur_symbol);
312 		}
313 		reg_attribute_list
314 	'}'
315 		{
316 			/*
317 			 * Default to allowing everything in for registers
318 			 * with no bit or mask definitions.
319 			 */
320 			if (cur_symbol->info.rinfo->valid_bitmask == 0)
321 				cur_symbol->info.rinfo->valid_bitmask = 0xFF;
322 
323 			if (cur_symbol->info.rinfo->size == 0)
324 				cur_symbol->info.rinfo->size = 1;
325 
326 			/*
327 			 * This might be useful for registers too.
328 			 */
329 			if (cur_symbol->type != REGISTER) {
330 				if (cur_symbol->info.rinfo->address == 0)
331 					cur_symbol->info.rinfo->address =
332 					    sram_or_scb_offset;
333 				sram_or_scb_offset +=
334 				    cur_symbol->info.rinfo->size;
335 			}
336 			cur_symbol = NULL;
337 		}
338 ;
339 
340 reg_attribute_list:
341 	reg_attribute
342 |	reg_attribute_list reg_attribute
343 ;
344 
345 reg_attribute:
346 	reg_address
347 |	size
348 |	access_mode
349 |	modes
350 |	field_defn
351 |	enum_defn
352 |	mask_defn
353 |	alias
354 |	accumulator
355 |	mode_pointer
356 |	allones
357 |	allzeros
358 |	none
359 |	sindex
360 ;
361 
362 reg_address:
363 	T_ADDRESS T_NUMBER
364 	{
365 		cur_symbol->info.rinfo->address = $2;
366 	}
367 ;
368 
369 size:
370 	T_SIZE T_NUMBER
371 	{
372 		cur_symbol->info.rinfo->size = $2;
373 		if (scb_or_sram_symbol != NULL) {
374 			u_int max_addr;
375 			u_int sym_max_addr;
376 
377 			max_addr = scb_or_sram_symbol->info.rinfo->address
378 				 + scb_or_sram_symbol->info.rinfo->size;
379 			sym_max_addr = cur_symbol->info.rinfo->address
380 				     + cur_symbol->info.rinfo->size;
381 
382 			if (sym_max_addr > max_addr)
383 				stop("SCB or SRAM space exhausted", EX_DATAERR);
384 		}
385 	}
386 ;
387 
388 access_mode:
389 	T_ACCESS_MODE T_MODE
390 	{
391 		cur_symbol->info.rinfo->mode = $2;
392 	}
393 ;
394 
395 modes:
396 	T_MODES mode_list
397 	{
398 		cur_symbol->info.rinfo->modes = $2;
399 	}
400 ;
401 
402 mode_list:
403 	mode_value
404 	{
405 		$$ = $1;
406 	}
407 |	mode_list ',' mode_value
408 	{
409 		$$ = $1 | $3;
410 	}
411 ;
412 
413 mode_value:
414 	T_NUMBER
415 	{
416 		if ($1 > 4) {
417 			stop("Valid register modes range between 0 and 4.",
418 			     EX_DATAERR);
419 			/* NOTREACHED */
420 		}
421 
422 		$$ = (0x1 << $1);
423 	}
424 |	T_SYMBOL
425 	{
426 		symbol_t *symbol;
427 
428 		symbol = $1;
429 		if (symbol->type != CONST) {
430 			stop("Only \"const\" symbols allowed in "
431 			     "mode definitions.", EX_DATAERR);
432 			/* NOTREACHED */
433 		}
434 		if (symbol->info.cinfo->value > 4) {
435 			stop("Valid register modes range between 0 and 4.",
436 			     EX_DATAERR);
437 			/* NOTREACHED */
438 		}
439 		$$ = (0x1 << symbol->info.cinfo->value);
440 	}
441 ;
442 
443 field_defn:
444 	T_FIELD
445 		{
446 			field_symbol = NULL;
447 			enum_next_value = 0;
448 			enum_increment = 1;
449 		}
450 	'{' enum_entry_list '}'
451 |	T_FIELD T_SYMBOL expression
452 		{
453 			process_field(FIELD, $2, $3.value);
454 			field_symbol = $2;
455 			enum_next_value = 0;
456 			enum_increment = 0x01 << (ffs($3.value) - 1);
457 		}
458 	'{' enum_entry_list '}'
459 |	T_FIELD T_SYMBOL expression
460 	{
461 		process_field(FIELD, $2, $3.value);
462 	}
463 ;
464 
465 enum_defn:
466 	T_ENUM
467 		{
468 			field_symbol = NULL;
469 			enum_next_value = 0;
470 			enum_increment = 1;
471 		}
472 	'{' enum_entry_list '}'
473 |	T_ENUM T_SYMBOL expression
474 		{
475 			process_field(ENUM, $2, $3.value);
476 			field_symbol = $2;
477 			enum_next_value = 0;
478 			enum_increment = 0x01 << (ffs($3.value) - 1);
479 		}
480 	'{' enum_entry_list '}'
481 ;
482 
483 enum_entry_list:
484 	enum_entry
485 |	enum_entry_list ',' enum_entry
486 ;
487 
488 enum_entry:
489 	T_SYMBOL
490 	{
491 		process_field(ENUM_ENTRY, $1, enum_next_value);
492 		enum_next_value += enum_increment;
493 	}
494 |	T_SYMBOL expression
495 	{
496 		process_field(ENUM_ENTRY, $1, $2.value);
497 		enum_next_value = $2.value + enum_increment;
498 	}
499 ;
500 
501 mask_defn:
502 	T_MASK T_SYMBOL expression
503 	{
504 		process_field(MASK, $2, $3.value);
505 	}
506 ;
507 
508 alias:
509 	T_ALIAS	T_SYMBOL
510 	{
511 		if ($2->type != UNINITIALIZED) {
512 			stop("Re-definition of register alias",
513 			     EX_DATAERR);
514 			/* NOTREACHED */
515 		}
516 		$2->type = ALIAS;
517 		initialize_symbol($2);
518 		$2->info.ainfo->parent = cur_symbol;
519 	}
520 ;
521 
522 accumulator:
523 	T_ACCUM
524 	{
525 		if (accumulator.symbol != NULL) {
526 			stop("Only one accumulator definition allowed",
527 			     EX_DATAERR);
528 			/* NOTREACHED */
529 		}
530 		accumulator.symbol = cur_symbol;
531 	}
532 ;
533 
534 mode_pointer:
535 	T_MODE_PTR
536 	{
537 		if (mode_ptr.symbol != NULL) {
538 			stop("Only one mode pointer definition allowed",
539 			     EX_DATAERR);
540 			/* NOTREACHED */
541 		}
542 		mode_ptr.symbol = cur_symbol;
543 	}
544 ;
545 
546 allones:
547 	T_ALLONES
548 	{
549 		if (allones.symbol != NULL) {
550 			stop("Only one definition of allones allowed",
551 			     EX_DATAERR);
552 			/* NOTREACHED */
553 		}
554 		allones.symbol = cur_symbol;
555 	}
556 ;
557 
558 allzeros:
559 	T_ALLZEROS
560 	{
561 		if (allzeros.symbol != NULL) {
562 			stop("Only one definition of allzeros allowed",
563 			     EX_DATAERR);
564 			/* NOTREACHED */
565 		}
566 		allzeros.symbol = cur_symbol;
567 	}
568 ;
569 
570 none:
571 	T_NONE
572 	{
573 		if (none.symbol != NULL) {
574 			stop("Only one definition of none allowed",
575 			     EX_DATAERR);
576 			/* NOTREACHED */
577 		}
578 		none.symbol = cur_symbol;
579 	}
580 ;
581 
582 sindex:
583 	T_SINDEX
584 	{
585 		if (sindex.symbol != NULL) {
586 			stop("Only one definition of sindex allowed",
587 			     EX_DATAERR);
588 			/* NOTREACHED */
589 		}
590 		sindex.symbol = cur_symbol;
591 	}
592 ;
593 
594 expression:
595 	expression '|' expression
596 	{
597 		 $$.value = $1.value | $3.value;
598 		 symlist_merge(&$$.referenced_syms,
599 			       &$1.referenced_syms,
600 			       &$3.referenced_syms);
601 	}
602 |	expression '&' expression
603 	{
604 		$$.value = $1.value & $3.value;
605 		symlist_merge(&$$.referenced_syms,
606 			       &$1.referenced_syms,
607 			       &$3.referenced_syms);
608 	}
609 |	expression '+' expression
610 	{
611 		$$.value = $1.value + $3.value;
612 		symlist_merge(&$$.referenced_syms,
613 			       &$1.referenced_syms,
614 			       &$3.referenced_syms);
615 	}
616 |	expression '-' expression
617 	{
618 		$$.value = $1.value - $3.value;
619 		symlist_merge(&($$.referenced_syms),
620 			       &($1.referenced_syms),
621 			       &($3.referenced_syms));
622 	}
623 |	expression '*' expression
624 	{
625 		$$.value = $1.value * $3.value;
626 		symlist_merge(&($$.referenced_syms),
627 			       &($1.referenced_syms),
628 			       &($3.referenced_syms));
629 	}
630 |	expression '/' expression
631 	{
632 		$$.value = $1.value / $3.value;
633 		symlist_merge(&($$.referenced_syms),
634 			       &($1.referenced_syms),
635 			       &($3.referenced_syms));
636 	}
637 | 	expression T_EXPR_LSHIFT expression
638 	{
639 		$$.value = $1.value << $3.value;
640 		symlist_merge(&$$.referenced_syms,
641 			       &$1.referenced_syms,
642 			       &$3.referenced_syms);
643 	}
644 | 	expression T_EXPR_RSHIFT expression
645 	{
646 		$$.value = $1.value >> $3.value;
647 		symlist_merge(&$$.referenced_syms,
648 			       &$1.referenced_syms,
649 			       &$3.referenced_syms);
650 	}
651 |	'(' expression ')'
652 	{
653 		$$ = $2;
654 	}
655 |	'~' expression
656 	{
657 		$$ = $2;
658 		$$.value = (~$$.value) & 0xFF;
659 	}
660 |	'-' expression %prec UMINUS
661 	{
662 		$$ = $2;
663 		$$.value = -$$.value;
664 	}
665 |	T_NUMBER
666 	{
667 		$$.value = $1;
668 		SLIST_INIT(&$$.referenced_syms);
669 	}
670 |	T_SYMBOL
671 	{
672 		symbol_t *symbol;
673 
674 		symbol = $1;
675 		switch (symbol->type) {
676 		case ALIAS:
677 			symbol = $1->info.ainfo->parent;
678 		case REGISTER:
679 		case SCBLOC:
680 		case SRAMLOC:
681 			$$.value = symbol->info.rinfo->address;
682 			break;
683 		case MASK:
684 		case FIELD:
685 		case ENUM:
686 		case ENUM_ENTRY:
687 			$$.value = symbol->info.finfo->value;
688 			break;
689 		case DOWNLOAD_CONST:
690 		case CONST:
691 			$$.value = symbol->info.cinfo->value;
692 			break;
693 		case UNINITIALIZED:
694 		default:
695 		{
696 			snprintf(errbuf, sizeof(errbuf),
697 				 "Undefined symbol %s referenced",
698 				 symbol->name);
699 			stop(errbuf, EX_DATAERR);
700 			/* NOTREACHED */
701 			break;
702 		}
703 		}
704 		SLIST_INIT(&$$.referenced_syms);
705 		symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
706 	}
707 ;
708 
709 constant:
710 	T_CONST T_SYMBOL expression
711 	{
712 		if ($2->type != UNINITIALIZED) {
713 			stop("Re-definition of symbol as a constant",
714 			     EX_DATAERR);
715 			/* NOTREACHED */
716 		}
717 		$2->type = CONST;
718 		initialize_symbol($2);
719 		$2->info.cinfo->value = $3.value;
720 	}
721 |	T_CONST T_SYMBOL T_DOWNLOAD
722 	{
723 		if ($1) {
724 			stop("Invalid downloaded constant declaration",
725 			     EX_DATAERR);
726 			/* NOTREACHED */
727 		}
728 		if ($2->type != UNINITIALIZED) {
729 			stop("Re-definition of symbol as a downloaded constant",
730 			     EX_DATAERR);
731 			/* NOTREACHED */
732 		}
733 		$2->type = DOWNLOAD_CONST;
734 		initialize_symbol($2);
735 		$2->info.cinfo->value = download_constant_count++;
736 	}
737 ;
738 
739 macrodefn_prologue:
740 	T_DEFINE T_SYMBOL
741 	{
742 		if ($2->type != UNINITIALIZED) {
743 			stop("Re-definition of symbol as a macro",
744 			     EX_DATAERR);
745 			/* NOTREACHED */
746 		}
747 		cur_symbol = $2;
748 		cur_symbol->type = MACRO;
749 		initialize_symbol(cur_symbol);
750 	}
751 ;
752 
753 macrodefn:
754 	macrodefn_prologue T_MACROBODY
755 	{
756 		add_macro_body($2);
757 	}
758 |	macrodefn_prologue '(' macro_arglist ')' T_MACROBODY
759 	{
760 		add_macro_body($5);
761 		cur_symbol->info.macroinfo->narg = $3;
762 	}
763 ;
764 
765 macro_arglist:
766 	{
767 		/* Macros can take no arguments */
768 		$$ = 0;
769 	}
770 |	T_ARG
771 	{
772 		$$ = 1;
773 		add_macro_arg($1, 0);
774 	}
775 |	macro_arglist ',' T_ARG
776 	{
777 		if ($1 == 0) {
778 			stop("Comma without preceding argument in arg list",
779 			     EX_DATAERR);
780 			/* NOTREACHED */
781 		}
782 		$$ = $1 + 1;
783 		add_macro_arg($3, $1);
784 	}
785 ;
786 
787 scratch_ram:
788 	T_SRAM '{'
789 		{
790 			snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME,
791 				 num_srams);
792 			cur_symbol = symtable_get(SRAM_SYMNAME);
793 			cur_symtype = SRAMLOC;
794 			cur_symbol->type = SRAMLOC;
795 			initialize_symbol(cur_symbol);
796 		}
797 		reg_address
798 		{
799 			sram_or_scb_offset = cur_symbol->info.rinfo->address;
800 		}
801 		size
802 		{
803 			scb_or_sram_symbol = cur_symbol;
804 		}
805 		scb_or_sram_attributes
806 	'}'
807 		{
808 			cur_symbol = NULL;
809 			scb_or_sram_symbol = NULL;
810 		}
811 ;
812 
813 scb:
814 	T_SCB '{'
815 		{
816 			cur_symbol = symtable_get(SCB_SYMNAME);
817 			cur_symtype = SCBLOC;
818 			if (cur_symbol->type != UNINITIALIZED) {
819 				stop("Only one SRAM definition allowed",
820 				     EX_SOFTWARE);
821 				/* NOTREACHED */
822 			}
823 			cur_symbol->type = SCBLOC;
824 			initialize_symbol(cur_symbol);
825 			/* 64 bytes of SCB space */
826 			cur_symbol->info.rinfo->size = 64;
827 		}
828 		reg_address
829 		{
830 			sram_or_scb_offset = cur_symbol->info.rinfo->address;
831 		}
832 		size
833 		{
834 			scb_or_sram_symbol = cur_symbol;
835 		}
836 		scb_or_sram_attributes
837 	'}'
838 		{
839 			cur_symbol = NULL;
840 			scb_or_sram_symbol = NULL;
841 		}
842 ;
843 
844 scb_or_sram_attributes:
845 	/* NULL definition is okay */
846 |	modes
847 |	scb_or_sram_reg_list
848 |	modes scb_or_sram_reg_list
849 ;
850 
851 scb_or_sram_reg_list:
852 	reg_definition
853 |	scb_or_sram_reg_list reg_definition
854 ;
855 
856 reg_symbol:
857 	T_SYMBOL
858 	{
859 		process_register(&$1);
860 		$$.symbol = $1;
861 		$$.offset = 0;
862 	}
863 |	T_SYMBOL '[' T_SYMBOL ']'
864 	{
865 		process_register(&$1);
866 		if ($3->type != CONST) {
867 			stop("register offset must be a constant", EX_DATAERR);
868 			/* NOTREACHED */
869 		}
870 		if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
871 			stop("Accessing offset beyond range of register",
872 			     EX_DATAERR);
873 			/* NOTREACHED */
874 		}
875 		$$.symbol = $1;
876 		$$.offset = $3->info.cinfo->value;
877 	}
878 |	T_SYMBOL '[' T_NUMBER ']'
879 	{
880 		process_register(&$1);
881 		if (($3 + 1) > $1->info.rinfo->size) {
882 			stop("Accessing offset beyond range of register",
883 			     EX_DATAERR);
884 			/* NOTREACHED */
885 		}
886 		$$.symbol = $1;
887 		$$.offset = $3;
888 	}
889 |	T_A
890 	{
891 		if (accumulator.symbol == NULL) {
892 			stop("No accumulator has been defined", EX_DATAERR);
893 			/* NOTREACHED */
894 		}
895 		$$.symbol = accumulator.symbol;
896 		$$.offset = 0;
897 	}
898 ;
899 
900 destination:
901 	reg_symbol
902 	{
903 		test_writable_symbol($1.symbol);
904 		$$ = $1;
905 	}
906 ;
907 
908 immediate:
909 	expression
910 	{ $$ = $1; }
911 ;
912 
913 immediate_or_a:
914 	expression
915 	{
916 		if ($1.value == 0 && is_download_const(&$1) == 0) {
917 			snprintf(errbuf, sizeof(errbuf),
918 				 "\nExpression evaluates to 0 and thus "
919 				 "references the accumulator.\n "
920 				 "If this is the desired effect, use 'A' "
921 				 "instead.\n");
922 			stop(errbuf, EX_DATAERR);
923 		}
924 		$$ = $1;
925 	}
926 |	T_A
927 	{
928 		SLIST_INIT(&$$.referenced_syms);
929 		symlist_add(&$$.referenced_syms, accumulator.symbol,
930 			    SYMLIST_INSERT_HEAD);
931 		$$.value = 0;
932 	}
933 ;
934 
935 source:
936 	reg_symbol
937 	{
938 		test_readable_symbol($1.symbol);
939 		$$ = $1;
940 	}
941 ;
942 
943 opt_source:
944 	{
945 		$$.symbol = NULL;
946 		$$.offset = 0;
947 	}
948 |	',' source
949 	{ $$ = $2; }
950 ;
951 
952 ret:
953 	{ $$ = 0; }
954 |	T_RET
955 	{ $$ = 1; }
956 ;
957 
958 set_src_mode:
959 	T_SET_SRC_MODE T_NUMBER ';'
960 	{
961 		src_mode = $2;
962 	}
963 ;
964 
965 set_dst_mode:
966 	T_SET_DST_MODE T_NUMBER ';'
967 	{
968 		dst_mode = $2;
969 	}
970 ;
971 
972 critical_section_start:
973 	T_BEGIN_CS ';'
974 	{
975 		critical_section_t *cs;
976 
977 		if (in_critical_section != FALSE) {
978 			stop("Critical Section within Critical Section",
979 			     EX_DATAERR);
980 			/* NOTREACHED */
981 		}
982 		cs = cs_alloc();
983 		cs->begin_addr = instruction_ptr;
984 		in_critical_section = TRUE;
985 	}
986 ;
987 
988 critical_section_end:
989 	T_END_CS ';'
990 	{
991 		critical_section_t *cs;
992 
993 		if (in_critical_section == FALSE) {
994 			stop("Unballanced 'end_cs'", EX_DATAERR);
995 			/* NOTREACHED */
996 		}
997 		cs = TAILQ_LAST(&cs_tailq, cs_tailq);
998 		cs->end_addr = instruction_ptr;
999 		in_critical_section = FALSE;
1000 	}
1001 ;
1002 
1003 export:
1004 	{ $$ = 0; }
1005 |	T_EXPORT
1006 	{ $$ = 1; }
1007 ;
1008 
1009 label:
1010 	export T_SYMBOL ':'
1011 	{
1012 		if ($2->type != UNINITIALIZED) {
1013 			stop("Program label multiply defined", EX_DATAERR);
1014 			/* NOTREACHED */
1015 		}
1016 		$2->type = LABEL;
1017 		initialize_symbol($2);
1018 		$2->info.linfo->address = instruction_ptr;
1019 		$2->info.linfo->exported = $1;
1020 	}
1021 ;
1022 
1023 address:
1024 	T_SYMBOL
1025 	{
1026 		$$.symbol = $1;
1027 		$$.offset = 0;
1028 	}
1029 |	T_SYMBOL '+' T_NUMBER
1030 	{
1031 		$$.symbol = $1;
1032 		$$.offset = $3;
1033 	}
1034 |	T_SYMBOL '-' T_NUMBER
1035 	{
1036 		$$.symbol = $1;
1037 		$$.offset = -$3;
1038 	}
1039 |	'.'
1040 	{
1041 		$$.symbol = NULL;
1042 		$$.offset = 0;
1043 	}
1044 |	'.' '+' T_NUMBER
1045 	{
1046 		$$.symbol = NULL;
1047 		$$.offset = $3;
1048 	}
1049 |	'.' '-' T_NUMBER
1050 	{
1051 		$$.symbol = NULL;
1052 		$$.offset = -$3;
1053 	}
1054 ;
1055 
1056 conditional:
1057 	T_IF T_CEXPR '{'
1058 	{
1059 		scope_t *new_scope;
1060 
1061 		add_conditional($2);
1062 		new_scope = scope_alloc();
1063 		new_scope->type = SCOPE_IF;
1064 		new_scope->begin_addr = instruction_ptr;
1065 		new_scope->func_num = $2->info.condinfo->func_num;
1066 	}
1067 |	T_ELSE T_IF T_CEXPR '{'
1068 	{
1069 		scope_t *new_scope;
1070 		scope_t *scope_context;
1071 		scope_t *last_scope;
1072 
1073 		/*
1074 		 * Ensure that the previous scope is either an
1075 		 * if or and else if.
1076 		 */
1077 		scope_context = SLIST_FIRST(&scope_stack);
1078 		last_scope = TAILQ_LAST(&scope_context->inner_scope,
1079 					scope_tailq);
1080 		if (last_scope == NULL
1081 		 || last_scope->type == T_ELSE) {
1082 
1083 			stop("'else if' without leading 'if'", EX_DATAERR);
1084 			/* NOTREACHED */
1085 		}
1086 		add_conditional($3);
1087 		new_scope = scope_alloc();
1088 		new_scope->type = SCOPE_ELSE_IF;
1089 		new_scope->begin_addr = instruction_ptr;
1090 		new_scope->func_num = $3->info.condinfo->func_num;
1091 	}
1092 |	T_ELSE '{'
1093 	{
1094 		scope_t *new_scope;
1095 		scope_t *scope_context;
1096 		scope_t *last_scope;
1097 
1098 		/*
1099 		 * Ensure that the previous scope is either an
1100 		 * if or and else if.
1101 		 */
1102 		scope_context = SLIST_FIRST(&scope_stack);
1103 		last_scope = TAILQ_LAST(&scope_context->inner_scope,
1104 					scope_tailq);
1105 		if (last_scope == NULL
1106 		 || last_scope->type == SCOPE_ELSE) {
1107 
1108 			stop("'else' without leading 'if'", EX_DATAERR);
1109 			/* NOTREACHED */
1110 		}
1111 		new_scope = scope_alloc();
1112 		new_scope->type = SCOPE_ELSE;
1113 		new_scope->begin_addr = instruction_ptr;
1114 	}
1115 ;
1116 
1117 conditional:
1118 	'}'
1119 	{
1120 		scope_t *scope_context;
1121 
1122 		scope_context = SLIST_FIRST(&scope_stack);
1123 		if (scope_context->type == SCOPE_ROOT) {
1124 			stop("Unexpected '}' encountered", EX_DATAERR);
1125 			/* NOTREACHED */
1126 		}
1127 
1128 		scope_context->end_addr = instruction_ptr;
1129 
1130 		/* Pop the scope */
1131 		SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
1132 
1133 		process_scope(scope_context);
1134 
1135 		if (SLIST_FIRST(&scope_stack) == NULL) {
1136 			stop("Unexpected '}' encountered", EX_DATAERR);
1137 			/* NOTREACHED */
1138 		}
1139 	}
1140 ;
1141 
1142 f1_opcode:
1143 	T_AND { $$ = AIC_OP_AND; }
1144 |	T_XOR { $$ = AIC_OP_XOR; }
1145 |	T_ADD { $$ = AIC_OP_ADD; }
1146 |	T_ADC { $$ = AIC_OP_ADC; }
1147 ;
1148 
1149 code:
1150 	f1_opcode destination ',' immediate_or_a opt_source ret ';'
1151 	{
1152 		format_1_instr($1, &$2, &$4, &$5, $6);
1153 	}
1154 ;
1155 
1156 code:
1157 	T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
1158 	{
1159 		format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
1160 	}
1161 ;
1162 
1163 code:
1164 	T_INC destination opt_source ret ';'
1165 	{
1166 		expression_t immed;
1167 
1168 		make_expression(&immed, 1);
1169 		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
1170 	}
1171 ;
1172 
1173 code:
1174 	T_DEC destination opt_source ret ';'
1175 	{
1176 		expression_t immed;
1177 
1178 		make_expression(&immed, -1);
1179 		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
1180 	}
1181 ;
1182 
1183 code:
1184 	T_CLC ret ';'
1185 	{
1186 		expression_t immed;
1187 
1188 		make_expression(&immed, -1);
1189 		format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
1190 	}
1191 |	T_CLC T_MVI destination ',' immediate_or_a ret ';'
1192 	{
1193 		format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
1194 	}
1195 ;
1196 
1197 code:
1198 	T_STC ret ';'
1199 	{
1200 		expression_t immed;
1201 
1202 		make_expression(&immed, 1);
1203 		format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
1204 	}
1205 |	T_STC destination ret ';'
1206 	{
1207 		expression_t immed;
1208 
1209 		make_expression(&immed, 1);
1210 		format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
1211 	}
1212 ;
1213 
1214 code:
1215 	T_BMOV destination ',' source ',' immediate ret ';'
1216 	{
1217 		format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
1218 	}
1219 ;
1220 
1221 code:
1222 	T_MOV destination ',' source ret ';'
1223 	{
1224 		expression_t immed;
1225 
1226 		make_expression(&immed, 1);
1227 		format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5);
1228 	}
1229 ;
1230 
1231 code:
1232 	T_MVI destination ',' immediate ret ';'
1233 	{
1234 		if ($4.value == 0
1235 		 && is_download_const(&$4) == 0) {
1236 			expression_t immed;
1237 
1238 			/*
1239 			 * Allow move immediates of 0 so that macros,
1240 			 * that can't know the immediate's value and
1241 			 * otherwise compensate, still work.
1242 			 */
1243 			make_expression(&immed, 1);
1244 			format_1_instr(AIC_OP_BMOV, &$2, &immed, &allzeros, $5);
1245 		} else {
1246 			format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
1247 		}
1248 	}
1249 ;
1250 
1251 code:
1252 	T_NOT destination opt_source ret ';'
1253 	{
1254 		expression_t immed;
1255 
1256 		make_expression(&immed, 0xff);
1257 		format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
1258 	}
1259 ;
1260 
1261 code:
1262 	T_CLR destination ret ';'
1263 	{
1264 		expression_t immed;
1265 
1266 		make_expression(&immed, 0xff);
1267 		format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
1268 	}
1269 ;
1270 
1271 code:
1272 	T_NOP ret ';'
1273 	{
1274 		expression_t immed;
1275 
1276 		make_expression(&immed, 0xff);
1277 		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2);
1278 	}
1279 ;
1280 
1281 code:
1282 	T_RET ';'
1283 	{
1284 		expression_t immed;
1285 
1286 		make_expression(&immed, 0xff);
1287 		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
1288 	}
1289 ;
1290 
1291 	/*
1292 	 * This grammer differs from the one in the aic7xxx
1293 	 * reference manual since the grammer listed there is
1294 	 * ambiguous and causes a shift/reduce conflict.
1295 	 * It also seems more logical as the "immediate"
1296 	 * argument is listed as the second arg like the
1297 	 * other formats.
1298 	 */
1299 
1300 f2_opcode:
1301 	T_SHL { $$ = AIC_OP_SHL; }
1302 |	T_SHR { $$ = AIC_OP_SHR; }
1303 |	T_ROL { $$ = AIC_OP_ROL; }
1304 |	T_ROR { $$ = AIC_OP_ROR; }
1305 ;
1306 
1307 code:
1308 	f2_opcode destination ',' expression opt_source ret ';'
1309 	{
1310 		format_2_instr($1, &$2, &$4, &$5, $6);
1311 	}
1312 ;
1313 
1314 jmp_jc_jnc_call:
1315 	T_JMP	{ $$ = AIC_OP_JMP; }
1316 |	T_JC	{ $$ = AIC_OP_JC; }
1317 |	T_JNC	{ $$ = AIC_OP_JNC; }
1318 |	T_CALL	{ $$ = AIC_OP_CALL; }
1319 ;
1320 
1321 jz_jnz:
1322 	T_JZ	{ $$ = AIC_OP_JZ; }
1323 |	T_JNZ	{ $$ = AIC_OP_JNZ; }
1324 ;
1325 
1326 je_jne:
1327 	T_JE	{ $$ = AIC_OP_JE; }
1328 |	T_JNE	{ $$ = AIC_OP_JNE; }
1329 ;
1330 
1331 code:
1332 	jmp_jc_jnc_call address ';'
1333 	{
1334 		expression_t immed;
1335 
1336 		make_expression(&immed, 0);
1337 		format_3_instr($1, &sindex, &immed, &$2);
1338 	}
1339 ;
1340 
1341 code:
1342 	T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
1343 	{
1344 		format_3_instr($5, &$2, &$4, &$6);
1345 	}
1346 ;
1347 
1348 code:
1349 	T_TEST source ',' immediate_or_a jz_jnz address ';'
1350 	{
1351 		format_3_instr($5, &$2, &$4, &$6);
1352 	}
1353 ;
1354 
1355 code:
1356 	T_CMP source ',' immediate_or_a je_jne address ';'
1357 	{
1358 		format_3_instr($5, &$2, &$4, &$6);
1359 	}
1360 ;
1361 
1362 code:
1363 	T_MOV source jmp_jc_jnc_call address ';'
1364 	{
1365 		expression_t immed;
1366 
1367 		make_expression(&immed, 0);
1368 		format_3_instr($3, &$2, &immed, &$4);
1369 	}
1370 ;
1371 
1372 code:
1373 	T_MVI immediate jmp_jc_jnc_call address ';'
1374 	{
1375 		format_3_instr($3, &allzeros, &$2, &$4);
1376 	}
1377 ;
1378 
1379 %%
1380 
1381 static void
1382 process_field(int field_type, symbol_t *sym, int value)
1383 {
1384 	/*
1385 	 * Add the current register to its
1386 	 * symbol list, if it already exists,
1387 	 * warn if we are setting it to a
1388 	 * different value, or in the bit to
1389 	 * the "allowed bits" of this register.
1390 	 */
1391 	if (sym->type == UNINITIALIZED) {
1392 		sym->type = field_type;
1393 		initialize_symbol(sym);
1394 		sym->info.finfo->value = value;
1395 		if (field_type != ENUM_ENTRY) {
1396 			if (field_type != MASK && value == 0) {
1397 				stop("Empty Field, or Enum", EX_DATAERR);
1398 				/* NOTREACHED */
1399 			}
1400 			sym->info.finfo->value = value;
1401 			sym->info.finfo->mask = value;
1402 		} else if (field_symbol != NULL) {
1403 			sym->info.finfo->mask = field_symbol->info.finfo->value;
1404 		} else {
1405 			sym->info.finfo->mask = 0xFF;
1406 		}
1407 	} else if (sym->type != field_type) {
1408 		stop("Field definition mirrors a definition of the same "
1409 		     " name, but a different type", EX_DATAERR);
1410 		/* NOTREACHED */
1411 	} else if (value != sym->info.finfo->value) {
1412 		stop("Field redefined with a conflicting value", EX_DATAERR);
1413 		/* NOTREACHED */
1414 	}
1415 	/* Fail if this symbol is already listed */
1416 	if (symlist_search(&(sym->info.finfo->symrefs),
1417 			   cur_symbol->name) != NULL) {
1418 		stop("Field defined multiple times for register", EX_DATAERR);
1419 		/* NOTREACHED */
1420 	}
1421 	symlist_add(&(sym->info.finfo->symrefs), cur_symbol,
1422 		    SYMLIST_INSERT_HEAD);
1423 	cur_symbol->info.rinfo->valid_bitmask |= sym->info.finfo->mask;
1424 	cur_symbol->info.rinfo->typecheck_masks = TRUE;
1425 	symlist_add(&(cur_symbol->info.rinfo->fields), sym, SYMLIST_SORT);
1426 }
1427 
1428 static void
1429 initialize_symbol(symbol_t *symbol)
1430 {
1431 	switch (symbol->type) {
1432 	case UNINITIALIZED:
1433 		stop("Call to initialize_symbol with type field unset",
1434 		     EX_SOFTWARE);
1435 		/* NOTREACHED */
1436 		break;
1437 	case REGISTER:
1438 	case SRAMLOC:
1439 	case SCBLOC:
1440 		symbol->info.rinfo =
1441 		    (struct reg_info *)malloc(sizeof(struct reg_info));
1442 		if (symbol->info.rinfo == NULL) {
1443 			stop("Can't create register info", EX_SOFTWARE);
1444 			/* NOTREACHED */
1445 		}
1446 		memset(symbol->info.rinfo, 0,
1447 		       sizeof(struct reg_info));
1448 		SLIST_INIT(&(symbol->info.rinfo->fields));
1449 		/*
1450 		 * Default to allowing access in all register modes
1451 		 * or to the mode specified by the SCB or SRAM space
1452 		 * we are in.
1453 		 */
1454 		if (scb_or_sram_symbol != NULL)
1455 			symbol->info.rinfo->modes =
1456 			    scb_or_sram_symbol->info.rinfo->modes;
1457 		else
1458 			symbol->info.rinfo->modes = ~0;
1459 		break;
1460 	case ALIAS:
1461 		symbol->info.ainfo =
1462 		    (struct alias_info *)malloc(sizeof(struct alias_info));
1463 		if (symbol->info.ainfo == NULL) {
1464 			stop("Can't create alias info", EX_SOFTWARE);
1465 			/* NOTREACHED */
1466 		}
1467 		memset(symbol->info.ainfo, 0,
1468 		       sizeof(struct alias_info));
1469 		break;
1470 	case MASK:
1471 	case FIELD:
1472 	case ENUM:
1473 	case ENUM_ENTRY:
1474 		symbol->info.finfo =
1475 		    (struct field_info *)malloc(sizeof(struct field_info));
1476 		if (symbol->info.finfo == NULL) {
1477 			stop("Can't create field info", EX_SOFTWARE);
1478 			/* NOTREACHED */
1479 		}
1480 		memset(symbol->info.finfo, 0, sizeof(struct field_info));
1481 		SLIST_INIT(&(symbol->info.finfo->symrefs));
1482 		break;
1483 	case CONST:
1484 	case DOWNLOAD_CONST:
1485 		symbol->info.cinfo =
1486 		    (struct const_info *)malloc(sizeof(struct const_info));
1487 		if (symbol->info.cinfo == NULL) {
1488 			stop("Can't create alias info", EX_SOFTWARE);
1489 			/* NOTREACHED */
1490 		}
1491 		memset(symbol->info.cinfo, 0,
1492 		       sizeof(struct const_info));
1493 		break;
1494 	case LABEL:
1495 		symbol->info.linfo =
1496 		    (struct label_info *)malloc(sizeof(struct label_info));
1497 		if (symbol->info.linfo == NULL) {
1498 			stop("Can't create label info", EX_SOFTWARE);
1499 			/* NOTREACHED */
1500 		}
1501 		memset(symbol->info.linfo, 0,
1502 		       sizeof(struct label_info));
1503 		break;
1504 	case CONDITIONAL:
1505 		symbol->info.condinfo =
1506 		    (struct cond_info *)malloc(sizeof(struct cond_info));
1507 		if (symbol->info.condinfo == NULL) {
1508 			stop("Can't create conditional info", EX_SOFTWARE);
1509 			/* NOTREACHED */
1510 		}
1511 		memset(symbol->info.condinfo, 0,
1512 		       sizeof(struct cond_info));
1513 		break;
1514 	case MACRO:
1515 		symbol->info.macroinfo =
1516 		    (struct macro_info *)malloc(sizeof(struct macro_info));
1517 		if (symbol->info.macroinfo == NULL) {
1518 			stop("Can't create macro info", EX_SOFTWARE);
1519 			/* NOTREACHED */
1520 		}
1521 		memset(symbol->info.macroinfo, 0,
1522 		       sizeof(struct macro_info));
1523 		STAILQ_INIT(&symbol->info.macroinfo->args);
1524 		break;
1525 	default:
1526 		stop("Call to initialize_symbol with invalid symbol type",
1527 		     EX_SOFTWARE);
1528 		/* NOTREACHED */
1529 		break;
1530 	}
1531 }
1532 
1533 static void
1534 add_macro_arg(const char *argtext, int argnum)
1535 {
1536 	struct macro_arg *marg;
1537 	int i;
1538 	int retval;
1539 
1540 
1541 	if (cur_symbol == NULL || cur_symbol->type != MACRO) {
1542 		stop("Invalid current symbol for adding macro arg",
1543 		     EX_SOFTWARE);
1544 		/* NOTREACHED */
1545 	}
1546 
1547 	marg = (struct macro_arg *)malloc(sizeof(*marg));
1548 	if (marg == NULL) {
1549 		stop("Can't create macro_arg structure", EX_SOFTWARE);
1550 		/* NOTREACHED */
1551 	}
1552 	marg->replacement_text = NULL;
1553 	retval = snprintf(regex_pattern, sizeof(regex_pattern),
1554 			  "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)",
1555 			  argtext);
1556 	if (retval >= sizeof(regex_pattern)) {
1557 		stop("Regex text buffer too small for arg",
1558 		     EX_SOFTWARE);
1559 		/* NOTREACHED */
1560 	}
1561 	retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED);
1562 	if (retval != 0) {
1563 		stop("Regex compilation failed", EX_SOFTWARE);
1564 		/* NOTREACHED */
1565 	}
1566 	STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links);
1567 }
1568 
1569 static void
1570 add_macro_body(const char *bodytext)
1571 {
1572 	if (cur_symbol == NULL || cur_symbol->type != MACRO) {
1573 		stop("Invalid current symbol for adding macro arg",
1574 		     EX_SOFTWARE);
1575 		/* NOTREACHED */
1576 	}
1577 	cur_symbol->info.macroinfo->body = strdup(bodytext);
1578 	if (cur_symbol->info.macroinfo->body == NULL) {
1579 		stop("Can't duplicate macro body text", EX_SOFTWARE);
1580 		/* NOTREACHED */
1581 	}
1582 }
1583 
1584 static void
1585 process_register(symbol_t **p_symbol)
1586 {
1587 	symbol_t *symbol = *p_symbol;
1588 
1589 	if (symbol->type == UNINITIALIZED) {
1590 		snprintf(errbuf, sizeof(errbuf), "Undefined register %s",
1591 			 symbol->name);
1592 		stop(errbuf, EX_DATAERR);
1593 		/* NOTREACHED */
1594 	} else if (symbol->type == ALIAS) {
1595 		*p_symbol = symbol->info.ainfo->parent;
1596 	} else if ((symbol->type != REGISTER)
1597 		&& (symbol->type != SCBLOC)
1598 		&& (symbol->type != SRAMLOC)) {
1599 		snprintf(errbuf, sizeof(errbuf),
1600 			 "Specified symbol %s is not a register",
1601 			 symbol->name);
1602 		stop(errbuf, EX_DATAERR);
1603 	}
1604 }
1605 
1606 static void
1607 format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
1608 	       symbol_ref_t *src, int ret)
1609 {
1610 	struct instruction *instr;
1611 	struct ins_format1 *f1_instr;
1612 
1613 	if (src->symbol == NULL)
1614 		src = dest;
1615 
1616 	/* Test register permissions */
1617 	test_writable_symbol(dest->symbol);
1618 	test_readable_symbol(src->symbol);
1619 
1620 	/* Ensure that immediate makes sense for this destination */
1621 	type_check(dest->symbol, immed, opcode);
1622 
1623 	/* Allocate sequencer space for the instruction and fill it out */
1624 	instr = seq_alloc();
1625 	f1_instr = &instr->format.format1;
1626 	f1_instr->ret = ret ? 1 : 0;
1627 	f1_instr->opcode = opcode;
1628 	f1_instr->destination = dest->symbol->info.rinfo->address
1629 			      + dest->offset;
1630 	f1_instr->source = src->symbol->info.rinfo->address
1631 			 + src->offset;
1632 	f1_instr->immediate = immed->value;
1633 
1634 	if (is_download_const(immed))
1635 		f1_instr->parity = 1;
1636 	else if (dest->symbol == mode_ptr.symbol) {
1637 		u_int src_value;
1638 		u_int dst_value;
1639 
1640 		/*
1641 		 * Attempt to update mode information if
1642 		 * we are operating on the mode register.
1643 		 */
1644 		if (src->symbol == allones.symbol)
1645 			src_value = 0xFF;
1646 		else if (src->symbol == allzeros.symbol)
1647 			src_value = 0;
1648 		else if (src->symbol == mode_ptr.symbol)
1649 			src_value = (dst_mode << 4) | src_mode;
1650 		else
1651 			goto cant_update;
1652 
1653 		switch (opcode) {
1654 		case AIC_OP_AND:
1655 			dst_value = src_value & immed->value;
1656 			break;
1657 		case AIC_OP_XOR:
1658 			dst_value = src_value ^ immed->value;
1659 			break;
1660 		case AIC_OP_ADD:
1661 			dst_value = (src_value + immed->value) & 0xFF;
1662 			break;
1663 		case AIC_OP_OR:
1664 			dst_value = src_value | immed->value;
1665 			break;
1666 		case AIC_OP_BMOV:
1667 			dst_value = src_value;
1668 			break;
1669 		default:
1670 			goto cant_update;
1671 		}
1672 		src_mode = dst_value & 0xF;
1673 		dst_mode = (dst_value >> 4) & 0xF;
1674 	}
1675 
1676 cant_update:
1677 	symlist_free(&immed->referenced_syms);
1678 	instruction_ptr++;
1679 }
1680 
1681 static void
1682 format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places,
1683 	       symbol_ref_t *src, int ret)
1684 {
1685 	struct instruction *instr;
1686 	struct ins_format2 *f2_instr;
1687 	uint8_t shift_control;
1688 
1689 	if (src->symbol == NULL)
1690 		src = dest;
1691 
1692 	/* Test register permissions */
1693 	test_writable_symbol(dest->symbol);
1694 	test_readable_symbol(src->symbol);
1695 
1696 	/* Allocate sequencer space for the instruction and fill it out */
1697 	instr = seq_alloc();
1698 	f2_instr = &instr->format.format2;
1699 	f2_instr->ret = ret ? 1 : 0;
1700 	f2_instr->opcode = AIC_OP_ROL;
1701 	f2_instr->destination = dest->symbol->info.rinfo->address
1702 			      + dest->offset;
1703 	f2_instr->source = src->symbol->info.rinfo->address
1704 			 + src->offset;
1705 	if (places->value > 8 || places->value <= 0) {
1706 		stop("illegal shift value", EX_DATAERR);
1707 		/* NOTREACHED */
1708 	}
1709 	switch (opcode) {
1710 	case AIC_OP_SHL:
1711 		if (places->value == 8)
1712 			shift_control = 0xf0;
1713 		else
1714 			shift_control = (places->value << 4) | places->value;
1715 		break;
1716 	case AIC_OP_SHR:
1717 		if (places->value == 8) {
1718 			shift_control = 0xf8;
1719 		} else {
1720 			shift_control = (places->value << 4)
1721 				      | (8 - places->value)
1722 				      | 0x08;
1723 		}
1724 		break;
1725 	case AIC_OP_ROL:
1726 		shift_control = places->value & 0x7;
1727 		break;
1728 	case AIC_OP_ROR:
1729 		shift_control = (8 - places->value) | 0x08;
1730 		break;
1731 	default:
1732 		shift_control = 0; /* Quiet Compiler */
1733 		stop("Invalid shift operation specified", EX_SOFTWARE);
1734 		/* NOTREACHED */
1735 		break;
1736 	};
1737 	f2_instr->shift_control = shift_control;
1738 	symlist_free(&places->referenced_syms);
1739 	instruction_ptr++;
1740 }
1741 
1742 static void
1743 format_3_instr(int opcode, symbol_ref_t *src,
1744 	       expression_t *immed, symbol_ref_t *address)
1745 {
1746 	struct instruction *instr;
1747 	struct ins_format3 *f3_instr;
1748 	int addr;
1749 
1750 	/* Test register permissions */
1751 	test_readable_symbol(src->symbol);
1752 
1753 	/* Ensure that immediate makes sense for this source */
1754 	type_check(src->symbol, immed, opcode);
1755 
1756 	/* Allocate sequencer space for the instruction and fill it out */
1757 	instr = seq_alloc();
1758 	f3_instr = &instr->format.format3;
1759 	if (address->symbol == NULL) {
1760 		/* 'dot' referrence.  Use the current instruction pointer */
1761 		addr = instruction_ptr + address->offset;
1762 	} else if (address->symbol->type == UNINITIALIZED) {
1763 		/* forward reference */
1764 		addr = address->offset;
1765 		instr->patch_label = address->symbol;
1766 	} else
1767 		addr = address->symbol->info.linfo->address + address->offset;
1768 	f3_instr->opcode = opcode;
1769 	f3_instr->address = addr;
1770 	f3_instr->source = src->symbol->info.rinfo->address
1771 			 + src->offset;
1772 	f3_instr->immediate = immed->value;
1773 
1774 	if (is_download_const(immed))
1775 		f3_instr->parity = 1;
1776 
1777 	symlist_free(&immed->referenced_syms);
1778 	instruction_ptr++;
1779 }
1780 
1781 static void
1782 test_readable_symbol(symbol_t *symbol)
1783 {
1784 
1785 	if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) {
1786 		snprintf(errbuf, sizeof(errbuf),
1787 			"Register %s unavailable in source reg mode %d",
1788 			symbol->name, src_mode);
1789 		stop(errbuf, EX_DATAERR);
1790 	}
1791 
1792 	if (symbol->info.rinfo->mode == WO) {
1793 		stop("Write Only register specified as source",
1794 		     EX_DATAERR);
1795 		/* NOTREACHED */
1796 	}
1797 }
1798 
1799 static void
1800 test_writable_symbol(symbol_t *symbol)
1801 {
1802 
1803 	if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) {
1804 		snprintf(errbuf, sizeof(errbuf),
1805 			"Register %s unavailable in destination reg mode %d",
1806 			symbol->name, dst_mode);
1807 		stop(errbuf, EX_DATAERR);
1808 	}
1809 
1810 	if (symbol->info.rinfo->mode == RO) {
1811 		stop("Read Only register specified as destination",
1812 		     EX_DATAERR);
1813 		/* NOTREACHED */
1814 	}
1815 }
1816 
1817 static void
1818 type_check(symbol_t *symbol, expression_t *expression, int opcode)
1819 {
1820 	symbol_node_t *node;
1821 	int and_op;
1822 
1823 	and_op = FALSE;
1824 	if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
1825 		and_op = TRUE;
1826 
1827 	/*
1828 	 * Make sure that we aren't attempting to write something
1829 	 * that hasn't been defined.  If this is an and operation,
1830 	 * this is a mask, so "undefined" bits are okay.
1831 	 */
1832 	if (and_op == FALSE
1833 	 && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
1834 		snprintf(errbuf, sizeof(errbuf),
1835 			 "Invalid bit(s) 0x%x in immediate written to %s",
1836 			 expression->value & ~symbol->info.rinfo->valid_bitmask,
1837 			 symbol->name);
1838 		stop(errbuf, EX_DATAERR);
1839 		/* NOTREACHED */
1840 	}
1841 
1842 	/*
1843 	 * Now make sure that all of the symbols referenced by the
1844 	 * expression are defined for this register.
1845 	 */
1846 	if (symbol->info.rinfo->typecheck_masks != FALSE) {
1847 		for(node = expression->referenced_syms.slh_first;
1848 		    node != NULL;
1849 		    node = node->links.sle_next) {
1850 			if ((node->symbol->type == MASK
1851 			  || node->symbol->type == FIELD
1852 			  || node->symbol->type == ENUM
1853 			  || node->symbol->type == ENUM_ENTRY)
1854 			 && symlist_search(&node->symbol->info.finfo->symrefs,
1855 					   symbol->name) == NULL) {
1856 				snprintf(errbuf, sizeof(errbuf),
1857 					 "Invalid field or mask %s "
1858 					 "for register %s",
1859 					 node->symbol->name, symbol->name);
1860 				stop(errbuf, EX_DATAERR);
1861 				/* NOTREACHED */
1862 			}
1863 		}
1864 	}
1865 }
1866 
1867 static void
1868 make_expression(expression_t *immed, int value)
1869 {
1870 	SLIST_INIT(&immed->referenced_syms);
1871 	immed->value = value & 0xff;
1872 }
1873 
1874 static void
1875 add_conditional(symbol_t *symbol)
1876 {
1877 	static int numfuncs;
1878 
1879 	if (numfuncs == 0) {
1880 		/* add a special conditional, "0" */
1881 		symbol_t *false_func;
1882 
1883 		false_func = symtable_get("0");
1884 		if (false_func->type != UNINITIALIZED) {
1885 			stop("Conditional expression '0' "
1886 			     "conflicts with a symbol", EX_DATAERR);
1887 			/* NOTREACHED */
1888 		}
1889 		false_func->type = CONDITIONAL;
1890 		initialize_symbol(false_func);
1891 		false_func->info.condinfo->func_num = numfuncs++;
1892 		symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
1893 	}
1894 
1895 	/* This condition has occurred before */
1896 	if (symbol->type == CONDITIONAL)
1897 		return;
1898 
1899 	if (symbol->type != UNINITIALIZED) {
1900 		stop("Conditional expression conflicts with a symbol",
1901 		     EX_DATAERR);
1902 		/* NOTREACHED */
1903 	}
1904 
1905 	symbol->type = CONDITIONAL;
1906 	initialize_symbol(symbol);
1907 	symbol->info.condinfo->func_num = numfuncs++;
1908 	symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
1909 }
1910 
1911 static void
1912 add_version(const char *verstring)
1913 {
1914 	const char prefix[] = " * ";
1915 	int newlen;
1916 	int oldlen;
1917 
1918 	newlen = strlen(verstring) + strlen(prefix);
1919 	oldlen = 0;
1920 	if (versions != NULL)
1921 		oldlen = strlen(versions);
1922 	versions = realloc(versions, newlen + oldlen + 2);
1923 	if (versions == NULL)
1924 		stop("Can't allocate version string", EX_SOFTWARE);
1925 	strcpy(&versions[oldlen], prefix);
1926 	strcpy(&versions[oldlen + strlen(prefix)], verstring);
1927 	versions[newlen + oldlen] = '\n';
1928 	versions[newlen + oldlen + 1] = '\0';
1929 }
1930 
1931 void
1932 yyerror(const char *string)
1933 {
1934 	stop(string, EX_DATAERR);
1935 }
1936 
1937 static int
1938 is_download_const(expression_t *immed)
1939 {
1940 	if ((immed->referenced_syms.slh_first != NULL)
1941 	 && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST))
1942 		return (TRUE);
1943 
1944 	return (FALSE);
1945 }
1946