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