xref: /freebsd/sys/dev/aic7xxx/aicasm/aicasm_gram.y (revision 77a0943ded95b9e6438f7db70c4a28e4d93946d4)
1 %{
2 /*
3  * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
4  *
5  * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions, and the following disclaimer,
13  *    without modification.
14  * 2. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * Alternatively, this software may be distributed under the terms of the
18  * GNU Public License ("GPL").
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $Id: //depot/src/aic7xxx/aicasm/aicasm_gram.y#6 $
33  *
34  * $FreeBSD$
35  */
36 
37 #include <inttypes.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sysexits.h>
42 
43 #include <sys/types.h>
44 #ifdef __linux__
45 #include "../queue.h"
46 #else
47 #include <sys/queue.h>
48 #endif
49 
50 #include "aicasm.h"
51 #include "aicasm_symbol.h"
52 #include "aicasm_insformat.h"
53 
54 int yylineno;
55 char *yyfilename;
56 static symbol_t *cur_symbol;
57 static symtype cur_symtype;
58 static symbol_t *accumulator;
59 static symbol_ref_t allones;
60 static symbol_ref_t allzeros;
61 static symbol_ref_t none;
62 static symbol_ref_t sindex;
63 static int instruction_ptr;
64 static int sram_or_scb_offset;
65 static int download_constant_count;
66 static int in_critical_section;
67 
68 static void process_bitmask(int mask_type, symbol_t *sym, int mask);
69 static void initialize_symbol(symbol_t *symbol);
70 static void process_register(symbol_t **p_symbol);
71 static void format_1_instr(int opcode, symbol_ref_t *dest,
72 			   expression_t *immed, symbol_ref_t *src, int ret);
73 static void format_2_instr(int opcode, symbol_ref_t *dest,
74 			   expression_t *places, symbol_ref_t *src, int ret);
75 static void format_3_instr(int opcode, symbol_ref_t *src,
76 			   expression_t *immed, symbol_ref_t *address);
77 static void test_readable_symbol(symbol_t *symbol);
78 static void test_writable_symbol(symbol_t *symbol);
79 static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
80 static void make_expression(expression_t *immed, int value);
81 static void add_conditional(symbol_t *symbol);
82 static int  is_download_const(expression_t *immed);
83 
84 #define YYDEBUG 1
85 #define SRAM_SYMNAME "SRAM_BASE"
86 #define SCB_SYMNAME "SCB_BASE"
87 %}
88 
89 %union {
90 	int		value;
91 	char		*str;
92 	symbol_t	*sym;
93 	symbol_ref_t	sym_ref;
94 	expression_t	expression;
95 }
96 
97 %token T_REGISTER
98 
99 %token <value> T_CONST
100 
101 %token T_DOWNLOAD
102 
103 %token T_SCB
104 
105 %token T_SRAM
106 
107 %token T_ALIAS
108 
109 %token T_SIZE
110 
111 %token <value> T_ADDRESS
112 
113 %token T_ACCESS_MODE
114 
115 %token <value> T_MODE
116 
117 %token T_BEGIN_CS
118 
119 %token T_END_CS
120 
121 %token T_BIT
122 
123 %token T_MASK
124 
125 %token <value> T_NUMBER
126 
127 %token <str> T_PATH
128 
129 %token <sym> T_CEXPR
130 
131 %token T_EOF T_INCLUDE
132 
133 %token <value> T_SHR T_SHL T_ROR T_ROL
134 
135 %token <value> T_MVI T_MOV T_CLR T_BMOV
136 
137 %token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
138 
139 %token <value> T_ADD T_ADC
140 
141 %token <value> T_INC T_DEC
142 
143 %token <value> T_STC T_CLC
144 
145 %token <value> T_CMP T_NOT T_XOR
146 
147 %token <value> T_TEST T_AND
148 
149 %token <value> T_OR
150 
151 %token T_RET
152 
153 %token T_NOP
154 
155 %token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX
156 
157 %token T_A
158 
159 %token <sym> T_SYMBOL
160 
161 %token T_NL
162 
163 %token T_IF T_ELSE T_ELSE_IF T_ENDIF
164 
165 %type <sym_ref> reg_symbol address destination source opt_source
166 
167 %type <expression> expression immediate immediate_or_a
168 
169 %type <value> ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
170 
171 %type <value> numerical_value
172 
173 %left '|'
174 %left '&'
175 %left '+' '-'
176 %right '~'
177 %nonassoc UMINUS
178 %%
179 
180 program:
181 	include
182 |	program include
183 |	register
184 |	program register
185 |	constant
186 |	program constant
187 |	scratch_ram
188 |	program scratch_ram
189 |	scb
190 |	program scb
191 |	label
192 |	program label
193 |	critical_section_start
194 |	program critical_section_start
195 |	critical_section_end
196 |	program critical_section_end
197 |	conditional
198 |	program conditional
199 |	code
200 |	program code
201 ;
202 
203 include:
204 	T_INCLUDE '<' T_PATH '>'
205 	{ include_file($3, BRACKETED_INCLUDE); }
206 |	T_INCLUDE '"' T_PATH '"'
207 	{ include_file($3, QUOTED_INCLUDE); }
208 ;
209 
210 register:
211 	T_REGISTER { cur_symtype = REGISTER; } reg_definition
212 ;
213 
214 reg_definition:
215 	T_SYMBOL '{'
216 		{
217 			if ($1->type != UNINITIALIZED) {
218 				stop("Register multiply defined", EX_DATAERR);
219 				/* NOTREACHED */
220 			}
221 			cur_symbol = $1;
222 			cur_symbol->type = cur_symtype;
223 			initialize_symbol(cur_symbol);
224 		}
225 		reg_attribute_list
226 	'}'
227 		{
228 			/*
229 			 * Default to allowing everything in for registers
230 			 * with no bit or mask definitions.
231 			 */
232 			if (cur_symbol->info.rinfo->valid_bitmask == 0)
233 				cur_symbol->info.rinfo->valid_bitmask = 0xFF;
234 
235 			if (cur_symbol->info.rinfo->size == 0)
236 				cur_symbol->info.rinfo->size = 1;
237 
238 			/*
239 			 * This might be useful for registers too.
240 			 */
241 			if (cur_symbol->type != REGISTER) {
242 				if (cur_symbol->info.rinfo->address == 0)
243 					cur_symbol->info.rinfo->address =
244 					    sram_or_scb_offset;
245 				sram_or_scb_offset +=
246 				    cur_symbol->info.rinfo->size;
247 			}
248 			cur_symbol = NULL;
249 		}
250 ;
251 
252 reg_attribute_list:
253 	reg_attribute
254 |	reg_attribute_list reg_attribute
255 ;
256 
257 reg_attribute:
258 	reg_address
259 |	size
260 |	access_mode
261 |	bit_defn
262 |	mask_defn
263 |	alias
264 |	accumulator
265 |	allones
266 |	allzeros
267 |	none
268 |	sindex
269 ;
270 
271 reg_address:
272 	T_ADDRESS T_NUMBER
273 	{
274 		cur_symbol->info.rinfo->address = $2;
275 	}
276 ;
277 
278 size:
279 	T_SIZE T_NUMBER
280 	{
281 		cur_symbol->info.rinfo->size = $2;
282 	}
283 ;
284 
285 access_mode:
286 	T_ACCESS_MODE T_MODE
287 	{
288 		cur_symbol->info.rinfo->mode = $2;
289 	}
290 ;
291 
292 bit_defn:
293 	T_BIT T_SYMBOL T_NUMBER
294 	{
295 		process_bitmask(BIT, $2, $3);
296 	}
297 ;
298 
299 mask_defn:
300 	T_MASK T_SYMBOL expression
301 	{
302 		process_bitmask(MASK, $2, $3.value);
303 	}
304 ;
305 
306 alias:
307 	T_ALIAS	T_SYMBOL
308 	{
309 		if ($2->type != UNINITIALIZED) {
310 			stop("Re-definition of register alias",
311 			     EX_DATAERR);
312 			/* NOTREACHED */
313 		}
314 		$2->type = ALIAS;
315 		initialize_symbol($2);
316 		$2->info.ainfo->parent = cur_symbol;
317 	}
318 ;
319 
320 accumulator:
321 	T_ACCUM
322 	{
323 		if (accumulator != NULL) {
324 			stop("Only one accumulator definition allowed",
325 			     EX_DATAERR);
326 			/* NOTREACHED */
327 		}
328 		accumulator = cur_symbol;
329 	}
330 ;
331 
332 allones:
333 	T_ALLONES
334 	{
335 		if (allones.symbol != NULL) {
336 			stop("Only one definition of allones allowed",
337 			     EX_DATAERR);
338 			/* NOTREACHED */
339 		}
340 		allones.symbol = cur_symbol;
341 	}
342 ;
343 
344 allzeros:
345 	T_ALLZEROS
346 	{
347 		if (allzeros.symbol != NULL) {
348 			stop("Only one definition of allzeros allowed",
349 			     EX_DATAERR);
350 			/* NOTREACHED */
351 		}
352 		allzeros.symbol = cur_symbol;
353 	}
354 ;
355 
356 none:
357 	T_NONE
358 	{
359 		if (none.symbol != NULL) {
360 			stop("Only one definition of none allowed",
361 			     EX_DATAERR);
362 			/* NOTREACHED */
363 		}
364 		none.symbol = cur_symbol;
365 	}
366 ;
367 
368 sindex:
369 	T_SINDEX
370 	{
371 		if (sindex.symbol != NULL) {
372 			stop("Only one definition of sindex allowed",
373 			     EX_DATAERR);
374 			/* NOTREACHED */
375 		}
376 		sindex.symbol = cur_symbol;
377 	}
378 ;
379 
380 expression:
381 	expression '|' expression
382 	{
383 		 $$.value = $1.value | $3.value;
384 		 symlist_merge(&$$.referenced_syms,
385 			       &$1.referenced_syms,
386 			       &$3.referenced_syms);
387 	}
388 |	expression '&' expression
389 	{
390 		$$.value = $1.value & $3.value;
391 		symlist_merge(&$$.referenced_syms,
392 			       &$1.referenced_syms,
393 			       &$3.referenced_syms);
394 	}
395 |	expression '+' expression
396 	{
397 		$$.value = $1.value + $3.value;
398 		symlist_merge(&$$.referenced_syms,
399 			       &$1.referenced_syms,
400 			       &$3.referenced_syms);
401 	}
402 |	expression '-' expression
403 	{
404 		$$.value = $1.value - $3.value;
405 		symlist_merge(&($$.referenced_syms),
406 			       &($1.referenced_syms),
407 			       &($3.referenced_syms));
408 	}
409 |	'(' expression ')'
410 	{
411 		$$ = $2;
412 	}
413 |	'~' expression
414 	{
415 		$$ = $2;
416 		$$.value = (~$$.value) & 0xFF;
417 	}
418 |	'-' expression %prec UMINUS
419 	{
420 		$$ = $2;
421 		$$.value = -$$.value;
422 	}
423 |	T_NUMBER
424 	{
425 		$$.value = $1;
426 		SLIST_INIT(&$$.referenced_syms);
427 	}
428 |	T_SYMBOL
429 	{
430 		symbol_t *symbol;
431 
432 		symbol = $1;
433 		switch (symbol->type) {
434 		case ALIAS:
435 			symbol = $1->info.ainfo->parent;
436 		case REGISTER:
437 		case SCBLOC:
438 		case SRAMLOC:
439 			$$.value = symbol->info.rinfo->address;
440 			break;
441 		case MASK:
442 		case BIT:
443 			$$.value = symbol->info.minfo->mask;
444 			break;
445 		case DOWNLOAD_CONST:
446 		case CONST:
447 			$$.value = symbol->info.cinfo->value;
448 			break;
449 		case UNINITIALIZED:
450 		default:
451 		{
452 			char buf[255];
453 
454 			snprintf(buf, sizeof(buf),
455 				 "Undefined symbol %s referenced",
456 				 symbol->name);
457 			stop(buf, EX_DATAERR);
458 			/* NOTREACHED */
459 			break;
460 		}
461 		}
462 		SLIST_INIT(&$$.referenced_syms);
463 		symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
464 	}
465 ;
466 
467 constant:
468 	T_CONST T_SYMBOL numerical_value
469 	{
470 		if ($2->type != UNINITIALIZED) {
471 			stop("Re-definition of symbol as a constant",
472 			     EX_DATAERR);
473 			/* NOTREACHED */
474 		}
475 		$2->type = CONST;
476 		initialize_symbol($2);
477 		$2->info.cinfo->value = $3;
478 		$2->info.cinfo->define = $1;
479 	}
480 |	T_CONST T_SYMBOL T_DOWNLOAD
481 	{
482 		if ($1) {
483 			stop("Invalid downloaded constant declaration",
484 			     EX_DATAERR);
485 			/* NOTREACHED */
486 		}
487 		if ($2->type != UNINITIALIZED) {
488 			stop("Re-definition of symbol as a downloaded constant",
489 			     EX_DATAERR);
490 			/* NOTREACHED */
491 		}
492 		$2->type = DOWNLOAD_CONST;
493 		initialize_symbol($2);
494 		$2->info.cinfo->value = download_constant_count++;
495 		$2->info.cinfo->define = FALSE;
496 	}
497 ;
498 
499 numerical_value:
500 	T_NUMBER
501 	{
502 		$$ = $1;
503 	}
504 |	'-' T_NUMBER
505 	{
506 		$$ = -$2;
507 	}
508 ;
509 
510 scratch_ram:
511 	T_SRAM '{'
512 		{
513 			cur_symbol = symtable_get(SRAM_SYMNAME);
514 			cur_symtype = SRAMLOC;
515 			if (cur_symbol->type != UNINITIALIZED) {
516 				stop("Only one SRAM definition allowed",
517 				     EX_DATAERR);
518 				/* NOTREACHED */
519 			}
520 			cur_symbol->type = SRAMLOC;
521 			initialize_symbol(cur_symbol);
522 		}
523 		reg_address
524 		{
525 			sram_or_scb_offset = cur_symbol->info.rinfo->address;
526 		}
527 		scb_or_sram_reg_list
528 	'}'
529 		{
530 			cur_symbol = NULL;
531 		}
532 ;
533 
534 scb:
535 	T_SCB '{'
536 		{
537 			cur_symbol = symtable_get(SCB_SYMNAME);
538 			cur_symtype = SCBLOC;
539 			if (cur_symbol->type != UNINITIALIZED) {
540 				stop("Only one SRAM definition allowed",
541 				     EX_SOFTWARE);
542 				/* NOTREACHED */
543 			}
544 			cur_symbol->type = SCBLOC;
545 			initialize_symbol(cur_symbol);
546 			/* 64 bytes of SCB space */
547 			cur_symbol->info.rinfo->size = 64;
548 		}
549 		reg_address
550 		{
551 			sram_or_scb_offset = cur_symbol->info.rinfo->address;
552 		}
553 		scb_or_sram_reg_list
554 	'}'
555 		{
556 			cur_symbol = NULL;
557 		}
558 ;
559 
560 scb_or_sram_reg_list:
561 	reg_definition
562 |	scb_or_sram_reg_list reg_definition
563 ;
564 
565 reg_symbol:
566 	T_SYMBOL
567 	{
568 		process_register(&$1);
569 		$$.symbol = $1;
570 		$$.offset = 0;
571 	}
572 |	T_SYMBOL '[' T_SYMBOL ']'
573 	{
574 		process_register(&$1);
575 		if ($3->type != CONST) {
576 			stop("register offset must be a constant", EX_DATAERR);
577 			/* NOTREACHED */
578 		}
579 		if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
580 			stop("Accessing offset beyond range of register",
581 			     EX_DATAERR);
582 			/* NOTREACHED */
583 		}
584 		$$.symbol = $1;
585 		$$.offset = $3->info.cinfo->value;
586 	}
587 |	T_SYMBOL '[' T_NUMBER ']'
588 	{
589 		process_register(&$1);
590 		if (($3 + 1) > $1->info.rinfo->size) {
591 			stop("Accessing offset beyond range of register",
592 			     EX_DATAERR);
593 			/* NOTREACHED */
594 		}
595 		$$.symbol = $1;
596 		$$.offset = $3;
597 	}
598 |	T_A
599 	{
600 		if (accumulator == NULL) {
601 			stop("No accumulator has been defined", EX_DATAERR);
602 			/* NOTREACHED */
603 		}
604 		$$.symbol = accumulator;
605 		$$.offset = 0;
606 	}
607 ;
608 
609 destination:
610 	reg_symbol
611 	{
612 		test_writable_symbol($1.symbol);
613 		$$ = $1;
614 	}
615 ;
616 
617 immediate:
618 	expression
619 	{ $$ = $1; }
620 ;
621 
622 immediate_or_a:
623 	expression
624 	{
625 		$$ = $1;
626 	}
627 |	T_A
628 	{
629 		SLIST_INIT(&$$.referenced_syms);
630 		$$.value = 0;
631 	}
632 ;
633 
634 source:
635 	reg_symbol
636 	{
637 		test_readable_symbol($1.symbol);
638 		$$ = $1;
639 	}
640 ;
641 
642 opt_source:
643 	{
644 		$$.symbol = NULL;
645 		$$.offset = 0;
646 	}
647 |	',' source
648 	{ $$ = $2; }
649 ;
650 
651 ret:
652 	{ $$ = 0; }
653 |	T_RET
654 	{ $$ = 1; }
655 ;
656 
657 critical_section_start:
658 	T_BEGIN_CS
659 	{
660 		critical_section_t *cs;
661 
662 		if (in_critical_section != FALSE) {
663 			stop("Critical Section within Critical Section",
664 			     EX_DATAERR);
665 			/* NOTREACHED */
666 		}
667 		cs = cs_alloc();
668 		cs->begin_addr = instruction_ptr;
669 		in_critical_section = TRUE;
670 	}
671 
672 critical_section_end:
673 	T_END_CS
674 	{
675 		critical_section_t *cs;
676 
677 		if (in_critical_section == FALSE) {
678 			stop("Unballanced 'end_cs'", EX_DATAERR);
679 			/* NOTREACHED */
680 		}
681 		cs = TAILQ_LAST(&cs_tailq, cs_tailq);
682 		cs->end_addr = instruction_ptr;
683 		in_critical_section = FALSE;
684 	}
685 
686 label:
687 	T_SYMBOL ':'
688 	{
689 		if ($1->type != UNINITIALIZED) {
690 			stop("Program label multiply defined", EX_DATAERR);
691 			/* NOTREACHED */
692 		}
693 		$1->type = LABEL;
694 		initialize_symbol($1);
695 		$1->info.linfo->address = instruction_ptr;
696 	}
697 ;
698 
699 address:
700 	T_SYMBOL
701 	{
702 		$$.symbol = $1;
703 		$$.offset = 0;
704 	}
705 |	T_SYMBOL '+' T_NUMBER
706 	{
707 		$$.symbol = $1;
708 		$$.offset = $3;
709 	}
710 |	T_SYMBOL '-' T_NUMBER
711 	{
712 		$$.symbol = $1;
713 		$$.offset = -$3;
714 	}
715 |	'.'
716 	{
717 		$$.symbol = NULL;
718 		$$.offset = 0;
719 	}
720 |	'.' '+' T_NUMBER
721 	{
722 		$$.symbol = NULL;
723 		$$.offset = $3;
724 	}
725 |	'.' '-' T_NUMBER
726 	{
727 		$$.symbol = NULL;
728 		$$.offset = -$3;
729 	}
730 ;
731 
732 conditional:
733 	T_IF T_CEXPR '{'
734 	{
735 		scope_t *new_scope;
736 
737 		add_conditional($2);
738 		new_scope = scope_alloc();
739 		new_scope->type = SCOPE_IF;
740 		new_scope->begin_addr = instruction_ptr;
741 		new_scope->func_num = $2->info.condinfo->func_num;
742 	}
743 |	T_ELSE T_IF T_CEXPR '{'
744 	{
745 		scope_t *new_scope;
746 		scope_t *scope_context;
747 		scope_t *last_scope;
748 
749 		/*
750 		 * Ensure that the previous scope is either an
751 		 * if or and else if.
752 		 */
753 		scope_context = SLIST_FIRST(&scope_stack);
754 		last_scope = TAILQ_LAST(&scope_context->inner_scope,
755 					scope_tailq);
756 		if (last_scope == NULL
757 		 || last_scope->type == T_ELSE) {
758 
759 			stop("'else if' without leading 'if'", EX_DATAERR);
760 			/* NOTREACHED */
761 		}
762 		add_conditional($3);
763 		new_scope = scope_alloc();
764 		new_scope->type = SCOPE_ELSE_IF;
765 		new_scope->begin_addr = instruction_ptr;
766 		new_scope->func_num = $3->info.condinfo->func_num;
767 	}
768 |	T_ELSE '{'
769 	{
770 		scope_t *new_scope;
771 		scope_t *scope_context;
772 		scope_t *last_scope;
773 
774 		/*
775 		 * Ensure that the previous scope is either an
776 		 * if or and else if.
777 		 */
778 		scope_context = SLIST_FIRST(&scope_stack);
779 		last_scope = TAILQ_LAST(&scope_context->inner_scope,
780 					scope_tailq);
781 		if (last_scope == NULL
782 		 || last_scope->type == SCOPE_ELSE) {
783 
784 			stop("'else' without leading 'if'", EX_DATAERR);
785 			/* NOTREACHED */
786 		}
787 		new_scope = scope_alloc();
788 		new_scope->type = SCOPE_ELSE;
789 		new_scope->begin_addr = instruction_ptr;
790 	}
791 ;
792 
793 conditional:
794 	'}'
795 	{
796 		scope_t *scope_context;
797 
798 		scope_context = SLIST_FIRST(&scope_stack);
799 		if (scope_context->type == SCOPE_ROOT) {
800 			stop("Unexpected '}' encountered", EX_DATAERR);
801 			/* NOTREACHED */
802 		}
803 
804 		scope_context->end_addr = instruction_ptr;
805 
806 		/* Pop the scope */
807 		SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
808 
809 		process_scope(scope_context);
810 
811 		if (SLIST_FIRST(&scope_stack) == NULL) {
812 			stop("Unexpected '}' encountered", EX_DATAERR);
813 			/* NOTREACHED */
814 		}
815 	}
816 ;
817 
818 f1_opcode:
819 	T_AND { $$ = AIC_OP_AND; }
820 |	T_XOR { $$ = AIC_OP_XOR; }
821 |	T_ADD { $$ = AIC_OP_ADD; }
822 |	T_ADC { $$ = AIC_OP_ADC; }
823 ;
824 
825 code:
826 	f1_opcode destination ',' immediate_or_a opt_source ret ';'
827 	{
828 		format_1_instr($1, &$2, &$4, &$5, $6);
829 	}
830 ;
831 
832 code:
833 	T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
834 	{
835 		format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
836 	}
837 ;
838 
839 code:
840 	T_INC destination opt_source ret ';'
841 	{
842 		expression_t immed;
843 
844 		make_expression(&immed, 1);
845 		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
846 	}
847 ;
848 
849 code:
850 	T_DEC destination opt_source ret ';'
851 	{
852 		expression_t immed;
853 
854 		make_expression(&immed, -1);
855 		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
856 	}
857 ;
858 
859 code:
860 	T_CLC ret ';'
861 	{
862 		expression_t immed;
863 
864 		make_expression(&immed, -1);
865 		format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
866 	}
867 |	T_CLC T_MVI destination ',' immediate_or_a ret ';'
868 	{
869 		format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
870 	}
871 ;
872 
873 code:
874 	T_STC ret ';'
875 	{
876 		expression_t immed;
877 
878 		make_expression(&immed, 1);
879 		format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
880 	}
881 |	T_STC destination ret ';'
882 	{
883 		expression_t immed;
884 
885 		make_expression(&immed, 1);
886 		format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
887 	}
888 ;
889 
890 code:
891 	T_BMOV destination ',' source ',' immediate ret ';'
892 	{
893 		format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
894 	}
895 ;
896 
897 code:
898 	T_MOV destination ',' source ret ';'
899 	{
900 		expression_t immed;
901 
902 		make_expression(&immed, 1);
903 		format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5);
904 	}
905 ;
906 
907 code:
908 	T_MVI destination ',' immediate_or_a ret ';'
909 	{
910 		format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
911 	}
912 ;
913 
914 code:
915 	T_NOT destination opt_source ret ';'
916 	{
917 		expression_t immed;
918 
919 		make_expression(&immed, 0xff);
920 		format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
921 	}
922 ;
923 
924 code:
925 	T_CLR destination ret ';'
926 	{
927 		expression_t immed;
928 
929 		make_expression(&immed, 0xff);
930 		format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
931 	}
932 ;
933 
934 code:
935 	T_NOP ret ';'
936 	{
937 		expression_t immed;
938 
939 		make_expression(&immed, 0xff);
940 		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2);
941 	}
942 ;
943 
944 code:
945 	T_RET ';'
946 	{
947 		expression_t immed;
948 
949 		make_expression(&immed, 0xff);
950 		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
951 	}
952 ;
953 
954 	/*
955 	 * This grammer differs from the one in the aic7xxx
956 	 * reference manual since the grammer listed there is
957 	 * ambiguous and causes a shift/reduce conflict.
958 	 * It also seems more logical as the "immediate"
959 	 * argument is listed as the second arg like the
960 	 * other formats.
961 	 */
962 
963 f2_opcode:
964 	T_SHL { $$ = AIC_OP_SHL; }
965 |	T_SHR { $$ = AIC_OP_SHR; }
966 |	T_ROL { $$ = AIC_OP_ROL; }
967 |	T_ROR { $$ = AIC_OP_ROR; }
968 ;
969 
970 code:
971 	f2_opcode destination ',' expression opt_source ret ';'
972 	{
973 		format_2_instr($1, &$2, &$4, &$5, $6);
974 	}
975 ;
976 
977 jmp_jc_jnc_call:
978 	T_JMP	{ $$ = AIC_OP_JMP; }
979 |	T_JC	{ $$ = AIC_OP_JC; }
980 |	T_JNC	{ $$ = AIC_OP_JNC; }
981 |	T_CALL	{ $$ = AIC_OP_CALL; }
982 ;
983 
984 jz_jnz:
985 	T_JZ	{ $$ = AIC_OP_JZ; }
986 |	T_JNZ	{ $$ = AIC_OP_JNZ; }
987 ;
988 
989 je_jne:
990 	T_JE	{ $$ = AIC_OP_JE; }
991 |	T_JNE	{ $$ = AIC_OP_JNE; }
992 ;
993 
994 code:
995 	jmp_jc_jnc_call address ';'
996 	{
997 		expression_t immed;
998 
999 		make_expression(&immed, 0);
1000 		format_3_instr($1, &sindex, &immed, &$2);
1001 	}
1002 ;
1003 
1004 code:
1005 	T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
1006 	{
1007 		format_3_instr($5, &$2, &$4, &$6);
1008 	}
1009 ;
1010 
1011 code:
1012 	T_TEST source ',' immediate_or_a jz_jnz address ';'
1013 	{
1014 		format_3_instr($5, &$2, &$4, &$6);
1015 	}
1016 ;
1017 
1018 code:
1019 	T_CMP source ',' immediate_or_a je_jne address ';'
1020 	{
1021 		format_3_instr($5, &$2, &$4, &$6);
1022 	}
1023 ;
1024 
1025 code:
1026 	T_MOV source jmp_jc_jnc_call address ';'
1027 	{
1028 		expression_t immed;
1029 
1030 		make_expression(&immed, 0);
1031 		format_3_instr($3, &$2, &immed, &$4);
1032 	}
1033 ;
1034 
1035 code:
1036 	T_MVI immediate jmp_jc_jnc_call address ';'
1037 	{
1038 		format_3_instr($3, &allzeros, &$2, &$4);
1039 	}
1040 ;
1041 
1042 %%
1043 
1044 static void
1045 process_bitmask(int mask_type, symbol_t *sym, int mask)
1046 {
1047 	/*
1048 	 * Add the current register to its
1049 	 * symbol list, if it already exists,
1050 	 * warn if we are setting it to a
1051 	 * different value, or in the bit to
1052 	 * the "allowed bits" of this register.
1053 	 */
1054 	if (sym->type == UNINITIALIZED) {
1055 		sym->type = mask_type;
1056 		initialize_symbol(sym);
1057 		if (mask_type == BIT) {
1058 			if (mask == 0) {
1059 				stop("Bitmask with no bits set", EX_DATAERR);
1060 				/* NOTREACHED */
1061 			}
1062 			if ((mask & ~(0x01 << (ffs(mask) - 1))) != 0) {
1063 				stop("Bitmask with more than one bit set",
1064 				     EX_DATAERR);
1065 				/* NOTREACHED */
1066 			}
1067 		}
1068 		sym->info.minfo->mask = mask;
1069 	} else if (sym->type != mask_type) {
1070 		stop("Bit definition mirrors a definition of the same "
1071 		     " name, but a different type", EX_DATAERR);
1072 		/* NOTREACHED */
1073 	} else if (mask != sym->info.minfo->mask) {
1074 		stop("Bitmask redefined with a conflicting value", EX_DATAERR);
1075 		/* NOTREACHED */
1076 	}
1077 	/* Fail if this symbol is already listed */
1078 	if (symlist_search(&(sym->info.minfo->symrefs),
1079 			   cur_symbol->name) != NULL) {
1080 		stop("Bitmask defined multiple times for register", EX_DATAERR);
1081 		/* NOTREACHED */
1082 	}
1083 	symlist_add(&(sym->info.minfo->symrefs), cur_symbol,
1084 		    SYMLIST_INSERT_HEAD);
1085 	cur_symbol->info.rinfo->valid_bitmask |= mask;
1086 	cur_symbol->info.rinfo->typecheck_masks = TRUE;
1087 }
1088 
1089 static void
1090 initialize_symbol(symbol_t *symbol)
1091 {
1092 	switch (symbol->type) {
1093         case UNINITIALIZED:
1094 		stop("Call to initialize_symbol with type field unset",
1095 		     EX_SOFTWARE);
1096 		/* NOTREACHED */
1097 		break;
1098         case REGISTER:
1099         case SRAMLOC:
1100         case SCBLOC:
1101 		symbol->info.rinfo =
1102 		    (struct reg_info *)malloc(sizeof(struct reg_info));
1103 		if (symbol->info.rinfo == NULL) {
1104 			stop("Can't create register info", EX_SOFTWARE);
1105 			/* NOTREACHED */
1106 		}
1107 		memset(symbol->info.rinfo, 0,
1108 		       sizeof(struct reg_info));
1109 		break;
1110         case ALIAS:
1111 		symbol->info.ainfo =
1112 		    (struct alias_info *)malloc(sizeof(struct alias_info));
1113 		if (symbol->info.ainfo == NULL) {
1114 			stop("Can't create alias info", EX_SOFTWARE);
1115 			/* NOTREACHED */
1116 		}
1117 		memset(symbol->info.ainfo, 0,
1118 		       sizeof(struct alias_info));
1119 		break;
1120         case MASK:
1121         case BIT:
1122 		symbol->info.minfo =
1123 		    (struct mask_info *)malloc(sizeof(struct mask_info));
1124 		if (symbol->info.minfo == NULL) {
1125 			stop("Can't create bitmask info", EX_SOFTWARE);
1126 			/* NOTREACHED */
1127 		}
1128 		memset(symbol->info.minfo, 0, sizeof(struct mask_info));
1129 		SLIST_INIT(&(symbol->info.minfo->symrefs));
1130 		break;
1131         case CONST:
1132         case DOWNLOAD_CONST:
1133 		symbol->info.cinfo =
1134 		    (struct const_info *)malloc(sizeof(struct const_info));
1135 		if (symbol->info.cinfo == NULL) {
1136 			stop("Can't create alias info", EX_SOFTWARE);
1137 			/* NOTREACHED */
1138 		}
1139 		memset(symbol->info.cinfo, 0,
1140 		       sizeof(struct const_info));
1141 		break;
1142 	case LABEL:
1143 		symbol->info.linfo =
1144 		    (struct label_info *)malloc(sizeof(struct label_info));
1145 		if (symbol->info.linfo == NULL) {
1146 			stop("Can't create label info", EX_SOFTWARE);
1147 			/* NOTREACHED */
1148 		}
1149 		memset(symbol->info.linfo, 0,
1150 		       sizeof(struct label_info));
1151 		break;
1152 	case CONDITIONAL:
1153 		symbol->info.condinfo =
1154 		    (struct cond_info *)malloc(sizeof(struct cond_info));
1155 		if (symbol->info.condinfo == NULL) {
1156 			stop("Can't create conditional info", EX_SOFTWARE);
1157 			/* NOTREACHED */
1158 		}
1159 		memset(symbol->info.condinfo, 0,
1160 		       sizeof(struct cond_info));
1161 		break;
1162 	default:
1163 		stop("Call to initialize_symbol with invalid symbol type",
1164 		     EX_SOFTWARE);
1165 		/* NOTREACHED */
1166 		break;
1167 	}
1168 }
1169 
1170 static void
1171 process_register(symbol_t **p_symbol)
1172 {
1173 	char buf[255];
1174 	symbol_t *symbol = *p_symbol;
1175 
1176 	if (symbol->type == UNINITIALIZED) {
1177 		snprintf(buf, sizeof(buf), "Undefined register %s",
1178 			 symbol->name);
1179 		stop(buf, EX_DATAERR);
1180 		/* NOTREACHED */
1181 	} else if (symbol->type == ALIAS) {
1182 		*p_symbol = symbol->info.ainfo->parent;
1183 	} else if ((symbol->type != REGISTER)
1184 		&& (symbol->type != SCBLOC)
1185 		&& (symbol->type != SRAMLOC)) {
1186 		snprintf(buf, sizeof(buf),
1187 			 "Specified symbol %s is not a register",
1188 			 symbol->name);
1189 		stop(buf, EX_DATAERR);
1190 	}
1191 }
1192 
1193 static void
1194 format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
1195 	       symbol_ref_t *src, int ret)
1196 {
1197 	struct instruction *instr;
1198 	struct ins_format1 *f1_instr;
1199 
1200 	if (src->symbol == NULL)
1201 		src = dest;
1202 
1203 	/* Test register permissions */
1204 	test_writable_symbol(dest->symbol);
1205 	test_readable_symbol(src->symbol);
1206 
1207 	/* Ensure that immediate makes sense for this destination */
1208 	type_check(dest->symbol, immed, opcode);
1209 
1210 	/* Allocate sequencer space for the instruction and fill it out */
1211 	instr = seq_alloc();
1212 	f1_instr = &instr->format.format1;
1213 	f1_instr->ret = ret ? 1 : 0;
1214 	f1_instr->opcode = opcode;
1215 	f1_instr->destination = dest->symbol->info.rinfo->address
1216 			      + dest->offset;
1217 	f1_instr->source = src->symbol->info.rinfo->address
1218 			 + src->offset;
1219 	f1_instr->immediate = immed->value;
1220 
1221 	if (is_download_const(immed))
1222 		f1_instr->parity = 1;
1223 
1224 	symlist_free(&immed->referenced_syms);
1225 	instruction_ptr++;
1226 }
1227 
1228 static void
1229 format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places,
1230 	       symbol_ref_t *src, int ret)
1231 {
1232 	struct instruction *instr;
1233 	struct ins_format2 *f2_instr;
1234 	uint8_t shift_control;
1235 
1236 	if (src->symbol == NULL)
1237 		src = dest;
1238 
1239 	/* Test register permissions */
1240 	test_writable_symbol(dest->symbol);
1241 	test_readable_symbol(src->symbol);
1242 
1243 	/* Allocate sequencer space for the instruction and fill it out */
1244 	instr = seq_alloc();
1245 	f2_instr = &instr->format.format2;
1246 	f2_instr->ret = ret ? 1 : 0;
1247 	f2_instr->opcode = AIC_OP_ROL;
1248 	f2_instr->destination = dest->symbol->info.rinfo->address
1249 			      + dest->offset;
1250 	f2_instr->source = src->symbol->info.rinfo->address
1251 			 + src->offset;
1252 	if (places->value > 8 || places->value <= 0) {
1253 		stop("illegal shift value", EX_DATAERR);
1254 		/* NOTREACHED */
1255 	}
1256 	switch (opcode) {
1257 	case AIC_OP_SHL:
1258 		if (places->value == 8)
1259 			shift_control = 0xf0;
1260 		else
1261 			shift_control = (places->value << 4) | places->value;
1262 		break;
1263 	case AIC_OP_SHR:
1264 		if (places->value == 8) {
1265 			shift_control = 0xf8;
1266 		} else {
1267 			shift_control = (places->value << 4)
1268 				      | (8 - places->value)
1269 				      | 0x08;
1270 		}
1271 		break;
1272 	case AIC_OP_ROL:
1273 		shift_control = places->value & 0x7;
1274 		break;
1275 	case AIC_OP_ROR:
1276 		shift_control = (8 - places->value) | 0x08;
1277 		break;
1278 	default:
1279 		shift_control = 0; /* Quiet Compiler */
1280 		stop("Invalid shift operation specified", EX_SOFTWARE);
1281 		/* NOTREACHED */
1282 		break;
1283 	};
1284 	f2_instr->shift_control = shift_control;
1285 	symlist_free(&places->referenced_syms);
1286 	instruction_ptr++;
1287 }
1288 
1289 static void
1290 format_3_instr(int opcode, symbol_ref_t *src,
1291 	       expression_t *immed, symbol_ref_t *address)
1292 {
1293 	struct instruction *instr;
1294 	struct ins_format3 *f3_instr;
1295 	int addr;
1296 
1297 	/* Test register permissions */
1298 	test_readable_symbol(src->symbol);
1299 
1300 	/* Ensure that immediate makes sense for this source */
1301 	type_check(src->symbol, immed, opcode);
1302 
1303 	/* Allocate sequencer space for the instruction and fill it out */
1304 	instr = seq_alloc();
1305 	f3_instr = &instr->format.format3;
1306 	if (address->symbol == NULL) {
1307 		/* 'dot' referrence.  Use the current instruction pointer */
1308 		addr = instruction_ptr + address->offset;
1309 	} else if (address->symbol->type == UNINITIALIZED) {
1310 		/* forward reference */
1311 		addr = address->offset;
1312 		instr->patch_label = address->symbol;
1313 	} else
1314 		addr = address->symbol->info.linfo->address + address->offset;
1315 	f3_instr->opcode = opcode;
1316 	f3_instr->address = addr;
1317 	f3_instr->source = src->symbol->info.rinfo->address
1318 			 + src->offset;
1319 	f3_instr->immediate = immed->value;
1320 
1321 	if (is_download_const(immed))
1322 		f3_instr->parity = 1;
1323 
1324 	symlist_free(&immed->referenced_syms);
1325 	instruction_ptr++;
1326 }
1327 
1328 static void
1329 test_readable_symbol(symbol_t *symbol)
1330 {
1331 	if (symbol->info.rinfo->mode == WO) {
1332 		stop("Write Only register specified as source",
1333 		     EX_DATAERR);
1334 		/* NOTREACHED */
1335 	}
1336 }
1337 
1338 static void
1339 test_writable_symbol(symbol_t *symbol)
1340 {
1341 	if (symbol->info.rinfo->mode == RO) {
1342 		stop("Read Only register specified as destination",
1343 		     EX_DATAERR);
1344 		/* NOTREACHED */
1345 	}
1346 }
1347 
1348 static void
1349 type_check(symbol_t *symbol, expression_t *expression, int opcode)
1350 {
1351 	symbol_node_t *node;
1352 	int and_op;
1353 	char buf[255];
1354 
1355 	and_op = FALSE;
1356 	if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
1357 		and_op = TRUE;
1358 
1359 	/*
1360 	 * Make sure that we aren't attempting to write something
1361 	 * that hasn't been defined.  If this is an and operation,
1362 	 * this is a mask, so "undefined" bits are okay.
1363 	 */
1364 	if (and_op == FALSE
1365 	 && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
1366 		snprintf(buf, sizeof(buf),
1367 			 "Invalid bit(s) 0x%x in immediate written to %s",
1368 			 expression->value & ~symbol->info.rinfo->valid_bitmask,
1369 			 symbol->name);
1370 		stop(buf, EX_DATAERR);
1371 		/* NOTREACHED */
1372 	}
1373 
1374 	/*
1375 	 * Now make sure that all of the symbols referenced by the
1376 	 * expression are defined for this register.
1377 	 */
1378 	if(symbol->info.rinfo->typecheck_masks != FALSE) {
1379 		for(node = expression->referenced_syms.slh_first;
1380 		    node != NULL;
1381 		    node = node->links.sle_next) {
1382 			if ((node->symbol->type == MASK
1383 			  || node->symbol->type == BIT)
1384 			 && symlist_search(&node->symbol->info.minfo->symrefs,
1385 					   symbol->name) == NULL) {
1386 				snprintf(buf, sizeof(buf),
1387 					 "Invalid bit or mask %s "
1388 					 "for register %s",
1389 					 node->symbol->name, symbol->name);
1390 				stop(buf, EX_DATAERR);
1391 				/* NOTREACHED */
1392 			}
1393 		}
1394 	}
1395 }
1396 
1397 static void
1398 make_expression(expression_t *immed, int value)
1399 {
1400 	SLIST_INIT(&immed->referenced_syms);
1401 	immed->value = value & 0xff;
1402 }
1403 
1404 static void
1405 add_conditional(symbol_t *symbol)
1406 {
1407 	static int numfuncs;
1408 
1409 	if (numfuncs == 0) {
1410 		/* add a special conditional, "0" */
1411 		symbol_t *false_func;
1412 
1413 		false_func = symtable_get("0");
1414 		if (false_func->type != UNINITIALIZED) {
1415 			stop("Conditional expression '0' "
1416 			     "conflicts with a symbol", EX_DATAERR);
1417 			/* NOTREACHED */
1418 		}
1419 		false_func->type = CONDITIONAL;
1420 		initialize_symbol(false_func);
1421 		false_func->info.condinfo->func_num = numfuncs++;
1422 		symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
1423 	}
1424 
1425 	/* This condition has occurred before */
1426 	if (symbol->type == CONDITIONAL)
1427 		return;
1428 
1429 	if (symbol->type != UNINITIALIZED) {
1430 		stop("Conditional expression conflicts with a symbol",
1431 		     EX_DATAERR);
1432 		/* NOTREACHED */
1433 	}
1434 
1435 	symbol->type = CONDITIONAL;
1436 	initialize_symbol(symbol);
1437 	symbol->info.condinfo->func_num = numfuncs++;
1438 	symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
1439 }
1440 
1441 void
1442 yyerror(const char *string)
1443 {
1444 	stop(string, EX_DATAERR);
1445 }
1446 
1447 static int
1448 is_download_const(expression_t *immed)
1449 {
1450 	if ((immed->referenced_syms.slh_first != NULL)
1451 	 && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST))
1452 		return (TRUE);
1453 
1454 	return (FALSE);
1455 }
1456