1 /*
2 Z88DK Z80 Macro Assembler
3 
4 Copyright (C) Gunther Strube, InterLogic 1993-99
5 Copyright (C) Paulo Custodio, 2011-2020
6 License: The Artistic License 2.0, http://www.perlfoundation.org/artistic_license_2_0
7 Repository: https://github.com/z88dk/z88dk
8 
9 Assembly directives.
10 */
11 
12 #include "codearea.h"
13 #include "die.h"
14 #include "directives.h"
15 #include "errors.h"
16 #include "fileutil.h"
17 #include "model.h"
18 #include "module.h"
19 #include "parse.h"
20 #include "strutil.h"
21 #include "symtab.h"
22 #include "types.h"
23 #include "utstring.h"
24 #include "z80asm.h"
25 
26 static void check_org_align();
27 
28 /*-----------------------------------------------------------------------------
29 *   LABEL: define a label at the current location
30 *----------------------------------------------------------------------------*/
asm_LABEL_offset(const char * name,int offset)31 void asm_LABEL_offset(const char* name, int offset)
32 {
33 	Symbol* sym;
34 
35 	if (get_phased_PC() >= 0)
36 		sym = define_symbol(name, get_phased_PC() + offset, TYPE_CONSTANT);
37 	else
38 		sym = define_symbol(name, get_PC() + offset, TYPE_ADDRESS);
39 
40 	sym->is_touched = true;
41 }
42 
asm_LABEL(const char * name)43 void asm_LABEL(const char* name)
44 {
45 	asm_LABEL_offset(name, 0);
46 }
47 
asm_cond_LABEL(Str * label)48 void asm_cond_LABEL(Str* label)
49 {
50 	if (Str_len(label)) {
51 		asm_LABEL(Str_data(label));
52 		Str_len(label) = 0;
53 	}
54 
55 	if (opts.debug_info && !scr_is_c_source()) {
56 		STR_DEFINE(name, STR_SIZE);
57 
58 		Str_sprintf(name, "__ASM_LINE_%ld", get_error_line());
59 		if (!find_local_symbol(Str_data(name)))
60 			asm_LABEL(Str_data(name));
61 
62 		STR_DELETE(name);
63 	}
64 }
65 
66 /*-----------------------------------------------------------------------------
67 *   DEFGROUP
68 *----------------------------------------------------------------------------*/
69 
70 static int DEFGROUP_PC;			/* next value to assign */
71 
72 /* start a new DEFGROUP context, give the value of the next defined constant */
asm_DEFGROUP_start(int next_value)73 void asm_DEFGROUP_start(int next_value)
74 {
75 	DEFGROUP_PC = next_value;
76 }
77 
78 /* define one constant with the next value, increment the value */
asm_DEFGROUP_define_const(const char * name)79 void asm_DEFGROUP_define_const(const char* name)
80 {
81 	xassert(name != NULL);
82 
83 	if (DEFGROUP_PC > 0xFFFF || DEFGROUP_PC < -0x8000)
84 		error_int_range(DEFGROUP_PC);
85 	else
86 		define_symbol(name, DEFGROUP_PC, TYPE_CONSTANT);
87 	DEFGROUP_PC++;
88 }
89 
90 /*-----------------------------------------------------------------------------
91 *   DEFVARS
92 *----------------------------------------------------------------------------*/
93 
94 static int DEFVARS_GLOBAL_PC;	/* DEFVARS address counter for global structs
95 								*  created by a chain of DEFVARS -1 */
96 static int DEFVARS_STRUCT_PC;	/* DEFVARS address counter for zero based structs
97 								*  restared on each DEFVARS 0 */
98 static int* DEFVARS_PC = &DEFVARS_STRUCT_PC;	/* select current DEFVARS PC*/
99 
100 /* start a new DEFVARS context, closing any previously open one */
asm_DEFVARS_start(int start_addr)101 void asm_DEFVARS_start(int start_addr)
102 {
103 	if (start_addr == -1)
104 		DEFVARS_PC = &DEFVARS_GLOBAL_PC;	/* continue from previous DEFVARS_GLOBAL_PC */
105 	else if (start_addr == 0)
106 	{
107 		DEFVARS_PC = &DEFVARS_STRUCT_PC;	/* start a new struct context */
108 		DEFVARS_STRUCT_PC = 0;
109 	}
110 	else if (start_addr > 0 && start_addr <= 0xFFFF)
111 	{
112 		DEFVARS_PC = &DEFVARS_GLOBAL_PC;	/* start a new DEFVARS_GLOBAL_PC */
113 		DEFVARS_GLOBAL_PC = start_addr;
114 	}
115 	else
116 		error_int_range(start_addr);
117 }
118 
119 /* define one constant in the current context */
asm_DEFVARS_define_const(const char * name,int elem_size,int count)120 void asm_DEFVARS_define_const(const char* name, int elem_size, int count)
121 {
122 	int var_size = elem_size * count;
123 	int next_pc = *DEFVARS_PC + var_size;
124 
125 	xassert(name != NULL);
126 
127 	if (var_size > 0xFFFF)
128 		error_int_range(var_size);
129 	else if (next_pc > 0xFFFF)
130 		error_int_range(next_pc);
131 	else
132 	{
133 		define_symbol(name, *DEFVARS_PC, TYPE_CONSTANT);
134 		*DEFVARS_PC = next_pc;
135 	}
136 }
137 
138 /*-----------------------------------------------------------------------------
139 *   directives without arguments
140 *----------------------------------------------------------------------------*/
asm_LSTON(void)141 void asm_LSTON(void)
142 {
143 	if (opts.list)
144 		opts.cur_list = true;
145 }
146 
asm_LSTOFF(void)147 void asm_LSTOFF(void)
148 {
149 	if (opts.list)
150 		opts.cur_list = false;
151 }
152 
153 /*-----------------------------------------------------------------------------
154 *   directives with number argument
155 *----------------------------------------------------------------------------*/
asm_LINE(int line_nr,const char * filename)156 void asm_LINE(int line_nr, const char* filename)
157 {
158 	STR_DEFINE(name, STR_SIZE);
159 
160 	src_set_filename(filename);
161 	src_set_line_nr(line_nr, 1);
162 	set_error_file(filename);
163 	set_error_line(line_nr);
164 
165 	STR_DELETE(name);
166 }
167 
asm_C_LINE(int line_nr,const char * filename)168 void asm_C_LINE(int line_nr, const char* filename)
169 {
170 	src_set_filename(filename);
171 	src_set_line_nr(line_nr, 0);		// do not increment line numbers
172 	src_set_c_source();
173 
174 	set_error_file(filename);
175 	set_error_line(line_nr);
176 
177 	if (opts.debug_info) {
178 		STR_DEFINE(name, STR_SIZE);
179 
180 		Str_sprintf(name, "__C_LINE_%ld", line_nr);
181 		if (!find_local_symbol(Str_data(name)))
182 			asm_LABEL(Str_data(name));
183 
184 		STR_DELETE(name);
185 	}
186 }
187 
asm_ORG(int address)188 void asm_ORG(int address)
189 {
190 	set_origin_directive(address);
191 	check_org_align();
192 }
193 
asm_PHASE(int address)194 void asm_PHASE(int address)
195 {
196 	set_phase_directive(address);
197 }
198 
asm_DEPHASE()199 void asm_DEPHASE()
200 {
201 	clear_phase_directive();
202 }
203 
204 /*-----------------------------------------------------------------------------
205 *   directives with string argument
206 *----------------------------------------------------------------------------*/
asm_INCLUDE(const char * filename)207 void asm_INCLUDE(const char* filename)
208 {
209 	parse_file(filename);
210 }
211 
asm_BINARY(const char * filename)212 void asm_BINARY(const char* filename)
213 {
214 	filename = path_search(filename, opts.inc_path);
215 	FILE* binfile = fopen(filename, "rb");
216 	if (!binfile) {
217 		error_read_file(filename);
218 	}
219 	else {
220 		append_file_contents(binfile, -1);		/* read binary code */
221 		xfclose(binfile);
222 	}
223 }
224 
225 /*-----------------------------------------------------------------------------
226 *   directives with name argument
227 *----------------------------------------------------------------------------*/
asm_MODULE(const char * name)228 void asm_MODULE(const char* name)
229 {
230 	CURRENTMODULE->modname = spool_add(name);		/* replace previous module name */
231 }
232 
asm_MODULE_default(void)233 void asm_MODULE_default(void)
234 {
235 	if (!CURRENTMODULE->modname)     /* Module name must be defined */
236 		CURRENTMODULE->modname = path_remove_ext(path_file(CURRENTMODULE->filename));
237 }
238 
asm_SECTION(const char * name)239 void asm_SECTION(const char* name)
240 {
241 	new_section(name);
242 }
243 
244 /*-----------------------------------------------------------------------------
245 *   directives with list of names argument, function called for each argument
246 *----------------------------------------------------------------------------*/
asm_GLOBAL(const char * name)247 void asm_GLOBAL(const char* name)
248 {
249 	declare_global_symbol(name);
250 }
251 
asm_EXTERN(const char * name)252 void asm_EXTERN(const char* name)
253 {
254 	declare_extern_symbol(name);
255 }
256 
asm_XREF(const char * name)257 void asm_XREF(const char* name)
258 {
259 	declare_extern_symbol(name);
260 }
261 
asm_LIB(const char * name)262 void asm_LIB(const char* name)
263 {
264 	declare_extern_symbol(name);
265 }
266 
asm_PUBLIC(const char * name)267 void asm_PUBLIC(const char* name)
268 {
269 	declare_public_symbol(name);
270 }
271 
asm_XDEF(const char * name)272 void asm_XDEF(const char* name)
273 {
274 	declare_public_symbol(name);
275 }
276 
asm_XLIB(const char * name)277 void asm_XLIB(const char* name)
278 {
279 	declare_public_symbol(name);
280 }
281 
asm_DEFINE(const char * name)282 void asm_DEFINE(const char* name)
283 {
284 	define_local_def_sym(name, 1);
285 }
286 
asm_UNDEFINE(const char * name)287 void asm_UNDEFINE(const char* name)
288 {
289 	SymbolHash_remove(CURRENTMODULE->local_symtab, name);
290 }
291 
292 /*-----------------------------------------------------------------------------
293 *   define a constant or expression
294 *----------------------------------------------------------------------------*/
asm_DEFC(const char * name,Expr * expr)295 void asm_DEFC(const char* name, Expr* expr)
296 {
297 	int value;
298 
299 	value = Expr_eval(expr, false);		/* DEFC constant expression */
300 	if ((expr->result.not_evaluable) || (expr->type >= TYPE_ADDRESS))
301 	{
302 		/* check if expression depends on itself */
303 		if (Expr_is_recusive(expr, name)) {
304 			error_expression_recursion(name);
305 		}
306 		else {
307 			/* store in object file to be computed at link time */
308 			expr->range = RANGE_WORD;
309 			expr->target_name = spool_add(name);
310 
311 			ExprList_push(&CURRENTMODULE->exprs, expr);
312 
313 			/* create symbol */
314 			define_symbol(expr->target_name, 0, TYPE_COMPUTED);
315 		}
316 	}
317 	else
318 	{
319 		define_symbol(name, value, TYPE_CONSTANT);
320 		OBJ_DELETE(expr);
321 	}
322 }
323 
asm_DC(const char * name,Expr * expr)324 void asm_DC(const char* name, Expr* expr)
325 {
326 	asm_DEFC(name, expr);
327 }
328 
329 /*-----------------------------------------------------------------------------
330 *   DEFS - create a block of empty bytes, called by the DEFS directive
331 *----------------------------------------------------------------------------*/
asm_DEFS(int count,int fill)332 void asm_DEFS(int count, int fill)
333 {
334 	if (count < 0 || count > 0x10000)
335 		error_int_range(count);
336 	else if (fill < -128 || fill > 255)
337 		error_int_range(fill);
338 	else
339 		append_defs(count, fill);
340 }
341 
342 /*-----------------------------------------------------------------------------
343 *   DEFB - add an expression or a string
344 *----------------------------------------------------------------------------*/
asm_DEFB_str(const char * str,int length)345 void asm_DEFB_str(const char* str, int length)
346 {
347 	while (length-- > 0)
348 		add_opcode((*str++) & 0xFF);
349 }
350 
asm_DEFB_expr(Expr * expr)351 void asm_DEFB_expr(Expr* expr)
352 {
353 	Pass2infoExpr(RANGE_BYTE_UNSIGNED, expr);
354 }
355 
asm_DEFP(Expr * expr)356 void asm_DEFP(Expr* expr)
357 {
358 	Pass2infoExpr(RANGE_PTR24, expr);
359 }
360 
asm_PTR(Expr * expr)361 void asm_PTR(Expr* expr)
362 {
363 	asm_DEFP(expr);
364 }
365 
asm_DP(Expr * expr)366 void asm_DP(Expr* expr)
367 {
368 	asm_DEFP(expr);
369 }
370 
371 /*-----------------------------------------------------------------------------
372 *   DEFW, DEFQ, DEFDB - add 2-byte and 4-byte expressions
373 *----------------------------------------------------------------------------*/
asm_DEFW(Expr * expr)374 void asm_DEFW(Expr* expr)
375 {
376 	Pass2infoExpr(RANGE_WORD, expr);
377 }
378 
asm_WORD(Expr * expr)379 void asm_WORD(Expr* expr)
380 {
381 	asm_DEFW(expr);
382 }
383 
asm_DW(Expr * expr)384 void asm_DW(Expr* expr)
385 {
386 	asm_DEFW(expr);
387 }
388 
asm_DEFDB(Expr * expr)389 void asm_DEFDB(Expr* expr)
390 {
391 	Pass2infoExpr(RANGE_WORD_BE, expr);
392 }
393 
asm_DDB(Expr * expr)394 void asm_DDB(Expr* expr)
395 {
396 	asm_DEFDB(expr);
397 }
398 
asm_DEFQ(Expr * expr)399 void asm_DEFQ(Expr* expr)
400 {
401 	Pass2infoExpr(RANGE_DWORD, expr);
402 }
403 
asm_DWORD(Expr * expr)404 void asm_DWORD(Expr* expr)
405 {
406 	asm_DEFQ(expr);
407 }
408 
asm_DQ(Expr * expr)409 void asm_DQ(Expr* expr)
410 {
411 	asm_DEFQ(expr);
412 }
413 
asm_ALIGN(int align,int filler)414 void asm_ALIGN(int align, int filler)
415 {
416 	if (align < 1 || align > 0xFFFF) {
417 		error_int_range(align);
418 	}
419 	else {
420 		// first ALIGN defines section alignment
421 		if (CURRENTSECTION->asmpc == 0) {
422 			if (CURRENTSECTION->align_found) {
423 				error_align_redefined();
424 			}
425 			else {
426 				CURRENTSECTION->align = align;
427 				CURRENTSECTION->align_found = true;
428 				check_org_align();
429 			}
430 		}
431 		// other ALIGN reserves space with DEFS
432 		else {
433 			int pc = get_phased_PC() >= 0 ? get_phased_PC() : get_PC();
434 			int above = pc % align;
435 			if (above > 0)
436 				asm_DEFS(align - above, filler);
437 		}
438 	}
439 }
440 
check_org_align()441 static void check_org_align()
442 {
443 	int org = CURRENTSECTION->origin;
444 	int align = CURRENTSECTION->align;
445 	if (org >= 0 && align > 1 && (org % align) != 0)
446 		error_org_not_aligned(org, align);
447 }
448 
449 /*-----------------------------------------------------------------------------
450 *   DMA
451 *----------------------------------------------------------------------------*/
asm_DMA_shift_exprs(UT_array * exprs)452 static Expr* asm_DMA_shift_exprs(UT_array* exprs)
453 {
454 	xassert(utarray_len(exprs) > 0);
455 
456 	Expr* expr = *((Expr**)utarray_front(exprs));	// copy first element
457 	*((Expr**)utarray_front(exprs)) = NULL;		// do not destroy
458 	utarray_erase(exprs, 0, 1);						// delete first element
459 
460 	return expr;
461 }
462 
asm_DMA_shift_byte(UT_array * exprs,int * out_value)463 static bool asm_DMA_shift_byte(UT_array* exprs, int* out_value)
464 {
465 	*out_value = 0;
466 
467 	Expr* expr = asm_DMA_shift_exprs(exprs);
468 	*out_value = Expr_eval(expr, true);
469 	bool not_evaluable = expr->result.not_evaluable;
470 	OBJ_DELETE(expr);
471 
472 	if (not_evaluable) {
473 		error_expected_const_expr();
474 		*out_value = 0;
475 		return false;
476 	}
477 	else if (*out_value < 0 || *out_value > 255) {
478 		error_int_range(*out_value);
479 		*out_value = 0;
480 		return false;
481 	}
482 	else
483 		return true;
484 }
485 
asm_DMA_command_1(int cmd,UT_array * exprs)486 static void asm_DMA_command_1(int cmd, UT_array* exprs)
487 {
488 	int N, W;
489 
490 	// retrieve first constant expression
491 	if (!asm_DMA_shift_byte(exprs, &N))
492 		return;
493 
494 	// retrieve next arguments
495 	switch (cmd) {
496 	case 0:
497 		/*
498 		dma.wr0 n [, w, x, y, z] with whitespace following comma including newline and
499 		maybe comment to the end of the line so params can be listed on following lines
500 		n: bit 7 must be 0, bits 1..0 must be 01 else error "base register byte is illegal"
501 
502 		If bit 3 of n is set then accept one following byte\
503 		If bit 4 of n is set then accept one following byte/ set together, expect word instead
504 		If bit 5 of n is set then accept one following byte\
505 		If bit 6 of n is set then accept one following byte/ set together, expect word instead
506 		*/
507 		if ((N & 0x83) != 0x01) {
508 			error_base_register_illegal(N);
509 			return;
510 		}
511 
512 		// add command byte
513 		add_opcode(N & 0xFF);
514 
515 		// parse wr0 parameters: check bits 3,4
516 		if ((N & 0x18) != 0 && utarray_len(exprs) == 0) {
517 			error_missing_arguments();
518 			return;
519 		}
520 		switch (N & 0x18) {
521 		case 0: break;
522 		case 0x08: asm_DEFB_expr(asm_DMA_shift_exprs(exprs)); break;		// bit 3
523 		case 0x10: asm_DEFB_expr(asm_DMA_shift_exprs(exprs)); break; 		// bit 4
524 		case 0x18: asm_DEFW(asm_DMA_shift_exprs(exprs)); break; 			// bits 3,4
525 		default: xassert(0);
526 		}
527 
528 		// parse wr0 parameters: check bits 5,6
529 		if ((N & 0x60) != 0 && utarray_len(exprs) == 0) {
530 			error_missing_arguments();
531 			return;
532 		}
533 		switch (N & 0x60) {
534 		case 0: break;
535 		case 0x20: asm_DEFB_expr(asm_DMA_shift_exprs(exprs)); break;		// bit 5
536 		case 0x40: asm_DEFB_expr(asm_DMA_shift_exprs(exprs)); break;		// bit 6
537 		case 0x60: asm_DEFW(asm_DMA_shift_exprs(exprs)); break;				// bits 5,6
538 		default: xassert(0);
539 		}
540 
541 		break;
542 
543 	case 1:
544 		/*
545 		dma.wr1 n [,w]
546 		or 0x04 into n
547 		n: bit 7 must be 0, bits 2..0 must be 100 else error "base register byte is illegal"
548 		If bit 6 of n is set then accept one following byte w.
549 
550 		In w bits 5..4 must be 0, bits 1..0 must not be 11 error "port A timing is illegal"
551 		In w if any of bits 7,6,3,2 are set warning "dma does not support half cycle timing"
552 		*/
553 		if (((N & 0x87) | 0x04) != 0x04) {
554 			error_base_register_illegal(N);
555 			return;
556 		}
557 		N |= 0x04;
558 
559 		// add command byte
560 		add_opcode(N & 0xFF);
561 
562 		if (N & 0x40) {
563 			if (utarray_len(exprs) == 0) {
564 				error_missing_arguments();
565 				return;
566 			}
567 			if (!asm_DMA_shift_byte(exprs, &W))
568 				return;
569 
570 			add_opcode(W & 0xFF);
571 			if ((W & 0x30) != 0 || (W & 0x03) == 0x03) {
572 				error_port_A_timing();
573 				return;
574 			}
575 			if (W & 0xCC)
576 				warn_dma_half_cycle_timing();
577 		}
578 		break;
579 
580 	case 2:
581 		/*
582 		dma.wr2 n [,w,x]
583 		n: bit 7 must be 0, bits 2..0 must be 000 else error "base register byte is illegal"
584 		If bit 6 of n is set then accept one following byte w
585 
586 		In w bit 4 must be 0, bits 1..0 must not be 11 error "port B timing is illegal"
587 		In w if any of bits 7,6,3,2 are set warning "dma does not support half cycle timing"
588 		If bit 5 of w is set then accept one following byte x that can be anything.
589 		*/
590 		if ((N & 0x87) != 0x00) {
591 			error_base_register_illegal(N);
592 			return;
593 		}
594 
595 		// add command byte
596 		add_opcode(N & 0xFF);
597 
598 		if (N & 0x40) {
599 			if (utarray_len(exprs) == 0) {
600 				error_missing_arguments();
601 				return;
602 			}
603 			if (!asm_DMA_shift_byte(exprs, &W))
604 				return;
605 
606 			add_opcode(W & 0xFF);
607 			if ((W & 0x10) != 0 || (W & 0x03) == 0x03) {
608 				error_port_B_timing();
609 				return;
610 			}
611 			if (W & 0xCC)
612 				warn_dma_half_cycle_timing();
613 
614 			if (W & 0x20) {
615 				if (utarray_len(exprs) == 0) {
616 					error_missing_arguments();
617 					return;
618 				}
619 				asm_DEFB_expr(asm_DMA_shift_exprs(exprs));
620 			}
621 		}
622 		break;
623 
624 	case 3:
625 		/*
626 		dma.wr3 n [,w,x]
627 		or 0x80 into n
628 		n: bit 7 must be 1, bits 1..0 must be 00 else error "base register byte is illegal"
629 		If any of bits 6,5,2 of n are set then warning "dma does not support some features"
630 
631 		If bit 3 of n is set then accept one following byte that can be anything.
632 		If bit 4 of n is set then accept one following byte that can be anything.
633 		*/
634 		if (((N & 0x83) | 0x80) != 0x80) {
635 			error_base_register_illegal(N);
636 			return;
637 		}
638 		N |= 0x80;
639 
640 		// add command byte
641 		add_opcode(N & 0xFF);
642 
643 		if (N & 0x64)
644 			warn_dma_unsupported_features();
645 
646 		if (N & 0x08) {
647 			if (utarray_len(exprs) == 0) {
648 				error_missing_arguments();
649 				return;
650 			}
651 			asm_DEFB_expr(asm_DMA_shift_exprs(exprs));
652 		}
653 
654 		if (N & 0x10) {
655 			if (utarray_len(exprs) == 0) {
656 				error_missing_arguments();
657 				return;
658 			}
659 			asm_DEFB_expr(asm_DMA_shift_exprs(exprs));
660 		}
661 		break;
662 
663 	case 4:
664 		/*
665 		dma.wr4 n, [w,x]
666 		or 0x81 into n
667 		n: bit 7 must be 1, bits 1..0 must be 01 else error "base register byte is illegal"
668 		If bit 4 of n is set then error "dma does not support interrupts"
669 		If bits 6..5 of n are 00 or 11 error "dma mode is illegal"
670 		If bit 2 of n is set then accept one following byte\
671 		If bit 3 of n is set then accept one following byte/ set together, expect word instead
672 
673 		Again if both bits 2 & 3 are set, w,x must be combined into a single word parameter.
674 		*/
675 		if (((N & 0x83) | 0x81) != 0x81) {
676 			error_base_register_illegal(N);
677 			return;
678 		}
679 		if (N & 0x10) {
680 			error_dma_unsupported_interrupts();
681 			return;
682 		}
683 		if ((N & 0x60) == 0 || (N & 0x60) == 0x60) {
684 			error_dma_illegal_mode();
685 			return;
686 		}
687 		N |= 0x81;
688 
689 		// add command byte
690 		add_opcode(N & 0xFF);
691 
692 		if ((N & 0x0C) == 0x0C) {
693 			if (utarray_len(exprs) == 0) {
694 				error_missing_arguments();
695 				return;
696 			}
697 			asm_DEFW(asm_DMA_shift_exprs(exprs));
698 		}
699 		else {
700 			if (N & 0x04) {
701 				if (utarray_len(exprs) == 0) {
702 					error_missing_arguments();
703 					return;
704 				}
705 				asm_DEFB_expr(asm_DMA_shift_exprs(exprs));
706 			}
707 			if (N & 0x08) {
708 				if (utarray_len(exprs) == 0) {
709 					error_missing_arguments();
710 					return;
711 				}
712 				asm_DEFB_expr(asm_DMA_shift_exprs(exprs));
713 			}
714 		}
715 		break;
716 
717 	case 5:
718 		/*
719 		dma.wr5 n
720 		or 0x82 into n
721 		n: bits 7..6 must be 10, bits 2..0 must be 010 else error "base register byte is illegal"
722 		If bit 3 of n is set then warning "dma does not support ready signals"
723 		*/
724 		if (((N & 0xC7) | 0x82) != 0x82) {
725 			error_base_register_illegal(N);
726 			return;
727 		}
728 		N |= 0x82;
729 
730 		if (N & 0x08)
731 			warn_dma_ready_signal_unsupported();
732 
733 		// add command byte
734 		add_opcode(N & 0xFF);
735 
736 		break;
737 
738 	case 6:
739 		/*
740 		dma.wr6 n [,w] or dma.cmd n [,w]
741 		n:
742 		accept 0xcf, 0xd3, 0x87, 0x83, 0xbb
743 		warning on 0xc3, 0xc7, 0xcb, 0xaf, 0xab, 0xa3, 0xb7, 0xbf, 0x8b, 0xa7, 0xb3
744 		"dma does not implement this command"
745 		anything else error "illegal dma command"
746 
747 		if n = 0xbb accept a following byte w
748 		If bit 7 of w is set error "read mask is illegal"
749 
750 		If any of these are missing following bytes in the comma list then maybe error
751 		"missing register group member(s)".
752 		if there are too many bytes "too many arguments".
753 		*/
754 		switch (N) {
755 		case 0x83:
756 		case 0x87:
757 		case 0xBB:
758 		case 0xCF:
759 		case 0xD3:
760 			break;
761 
762 		case 0x8B:
763 		case 0xA3:
764 		case 0xA7:
765 		case 0xAB:
766 		case 0xAF:
767 		case 0xB3:
768 		case 0xB7:
769 		case 0xBF:
770 		case 0xC3:
771 		case 0xC7:
772 		case 0xCB:
773 			warn_dma_unsupported_command();
774 			break;
775 
776 		default:
777 			error_dma_illegal_command();
778 			return;
779 		}
780 
781 		// add command byte
782 		add_opcode(N & 0xFF);
783 
784 		if (N == 0xBB) {
785 			if (utarray_len(exprs) == 0) {
786 				error_missing_arguments();
787 				return;
788 			}
789 			if (!asm_DMA_shift_byte(exprs, &W))
790 				return;
791 
792 			if (W & 0x80) {
793 				error_dma_illegal_read_mask();
794 				return;
795 			}
796 
797 			add_opcode(W & 0xFF);
798 		}
799 		break;
800 
801 	default:
802 		xassert(0);
803 	}
804 
805 	// check for extra arguments
806 	if (utarray_len(exprs) > 0)
807 		error_extra_arguments();
808 }
809 
asm_DMA_command(int cmd,UT_array * exprs)810 void asm_DMA_command(int cmd, UT_array* exprs)
811 {
812 	if (opts.cpu != CPU_Z80N) {
813 		error_illegal_ident();
814 		return;
815 	}
816 
817 	xassert(utarray_len(exprs) > 0);
818 	asm_DMA_command_1(cmd, exprs);
819 	utarray_clear(exprs);			// clear any expr left over in case of error
820 }
821