1 /*
2 * Small C+ Compiler
3 *
4 * Z80 Code Generator
5 *
6 * $Id: codegen.c,v 1.46 2016-09-19 09:17:50 dom Exp $
7 *
8 * 21/4/99 djm
9 * Added some conditional code for tests of zero with a char, the
10 * expand char to int code will be removed at optimizatin stage
11 *
12 * 22/4/99 djm
13 * Major rewrite!! All operations have one single routine now
14 * so the compile might actually run quicker, and uses less
15 * of those dodgy pointers to functions
16 *
17 * 23/4/99 djm
18 * With a bit of luck this file will no contain all assembler
19 * related output, this means that if Gunther gets macros worked
20 * into z80asm, we can change the output of the compiler to be
21 * macros which we can then optimize a lot easier..hazzah!
22 *
23 * 21/1/2014 Stefano
24 * z80asm syntax is evolving, now we declare the public objects
25 * with 'EXTERN' and 'PUBLIC'.
26 */
27
28 #include "ccdefs.h"
29 #include <time.h>
30 #include <math.h>
31
32
33
34 #define FRAME_REGISTER ( c_framepointer_is_ix ? "ix" : "iy")
35
36 extern int check_lastop_was_comparison(LVALUE* lval);
37
38
39 extern char Filenorig[];
40
41 #ifdef USEFRAME
42 extern int CheckOffset(int);
43 extern void PutFrame(char,int);
44 extern void OutIndex(int);
45 #endif
46
47
48 static void swap(void);
49 static void dpush_under(Kind val_type);
50 static void push(const char *ret);
51 static void pop(const char *ret);
52 static void immed2(void);
53 static void constbc(int32_t val);
54 static void addbchl(int val);
55 static void dcallrts(char *sname,Kind to);
56 static void quikmult(int type, int32_t size, char preserve);
57 static void threereg(void);
58 static void fivereg(void);
59 static void sixreg(void);
60 static void loada(int n);
61 static void setcond(int val);
62
63 /*
64 * Data for this module
65 */
66
67 static int donelibheader;
68 static const char *current_section = ""; /**< Name of the current section */
69 static const char *current_nspace = NULL;
70
71 /* Mappings between default library names - allows use of sdcc maths library with sccz80 */
72 struct _mapping {
73 char *opname;
74 char *fp_48bit;
75 char *fp_16bit;
76 char *fp_32bit;
77 char *fp_64bit;
78 } mappings[] = {
79 { "dload","dload", "l_gint", "l_glong" , "l_f64_load" },
80 { "dstore","dstore","l_pint", "l_plong", "l_f64_store" },
81 { "fadd", "dadd", "l_f16_add", "l_f32_add", "l_f64_add" },
82 { "fsub", "dsub", "l_f16_sub", "l_f32_sub", "l_f64_sub" },
83 { "fmul", "dmul", "l_f16_mul", "l_f32_mul", "l_f64_mul" },
84 { "fdiv", "ddiv", "l_f16_div", "l_f32_div", "l_f64_div" },
85 { "fle", "dleq", "l_f16_le", "l_f32_le", "l_f64_le" },
86 { "flt", "dlt", "l_f16_lt", "l_f32_lt", "l_f64_lt" },
87 { "fge", "dge", "l_f16_ge", "l_f32_ge", "l_f64_ge" },
88 { "fgt", "dgt", "l_f16_gt", "l_f32_gt", "l_f64_gt" },
89 { "feq", "deq", "l_f16_eq", "l_f32_eq", "l_f64_eq" },
90 { "fne", "dne", "l_f16_ne", "l_f32_ne", "l_f64_ne" },
91 { "schar2f", "l_int2long_s_float","l_f16_schar2f","l_f32_schar2f", "l_f64_schar2f" },
92 { "uchar2f", "l_int2long_u_float","l_f16_uchar2f","l_f32_uchar2f", "l_f64_uchar2f" },
93 { "sint2f", "l_int2long_s_float","l_f16_sint2f", "l_f32_sint2f", "l_f64_sint2f" },
94 { "uint2f", "l_int2long_u_float","l_f16_uint2f", "l_f32_uint2f", "l_f64_uint2f" },
95 { "slong2f", "float", "l_f16_slong2f", "l_f32_slong2f", "l_f64_slong2f" },
96 { "ulong2f", "ufloat","l_f16_ulong2f", "l_f32_ulong2f", "l_f64_ulong2f" },
97 { "sllong2f", "l_f48_sllong2f", "l_f16_sllong2f", "l_f32_sllong2f", "l_f64_sllong2f" },
98 { "ullong2f", "l_f48_ullong2f", "l_f16_ullong2f", "l_f32_ullong2f", "l_f64_ullong2f" },
99 { "f2sint", "ifix", "l_f16_f2sint", "l_f32_f2sint", "l_f64_f2sint" },
100 { "f2uint", "ifix", "l_f16_f2uint", "l_f32_f2uint", "l_f64_f2uint" },
101 { "f2slong", "ifix", "l_f16_f2slong", "l_f32_f2slong", "l_f64_f2slong" },
102 { "f2ulong", "ifix", "l_f16_f2ulong", "l_f32_f2ulong", "l_f64_f2ulong" },
103 { "f2slllong", "l_f48_f2sllong", "l_f16_f2sllong", "l_f32_f2sllong", "l_f64_f2sllong" },
104 { "f2ullong", "l_f48_f2ullong", "l_f16_f2ullong", "l_f32_f2ullong", "l_f64_f2ullong" },
105 { "fpush", "dpush", NULL, NULL, "l_f64_dpush" },
106 { "dpush_under_long", "dpush3", NULL, NULL, "l_f64_dpush3" }, // Inlined
107 { "dpush_under_int", "dpush2", NULL, NULL, "l_f64_dpush2" }, // Inlined
108 { "fswap", "dswap", NULL, "l_f32_swap", "l_f64_swap" },
109 { "fnegate", "minusfa", "l_f16_negate", "l_f32_negate", "l_f64_negate" },
110 { "ldexp", "l_f48_ldexp", "l_f16_ldexp", "l_f32_ldexp", "l_f64_ldexp" },
111 { "f16tof", "l_f48_f16tof", "l_f16_f16tof", "l_f32_f16tof", "l_f64_f16tof" },
112 { "ftof16", "l_f48_ftof16", "l_f16_ftof16", "l_f32_ftof16", "l_f64_ftof16" },
113 { "inversef", NULL, "l_f16_invf", "l_f32_invf", NULL }, // Called only for IEEE mode
114 { NULL }
115 };
116
map_library_routine(const char * wanted,Kind to)117 static const char *map_library_routine(const char *wanted, Kind to)
118 {
119 struct _mapping *map = &mappings[0];
120
121 while ( map->opname != NULL ) {
122 if ( strcmp(wanted, map->opname) == 0) {
123 if (to == KIND_FLOAT16 ) {
124 return map->fp_16bit;
125 } else if ( c_fp_size == 4 ) {
126 return map->fp_32bit;
127 } else if ( c_fp_size == 8 ) {
128 return map->fp_64bit;
129 }
130 return map->fp_48bit;
131 }
132 map++;
133 }
134 return wanted;
135 }
136
137 /* Output a comment line for the assembler */
gen_comment(const char * message)138 void gen_comment(const char *message)
139 {
140 outfmt(";%s\n",message);
141 }
142
143 /* Put out assembler info before any code is generated */
144
gen_file_header(void)145 void gen_file_header(void)
146 {
147 time_t tim;
148 char* timestr;
149
150 outfmt(";%s\n",Banner);
151 outfmt(";%s\n",Version);
152 outfmt(";\n");
153 outfmt(";\tReconstructed for z80 Module Assembler\n");
154
155 donelibheader = 0;
156 if ((tim = time(NULL)) != -1) {
157 timestr = ctime(&tim);
158 outfmt(";\n");
159 outfmt(";\tModule compile time: %s\n",timestr);
160 }
161 nl();
162 }
163
164
DoLibHeader(void)165 void DoLibHeader(void)
166 {
167 char filen[FILENAME_LEN + 1];
168 char* segment;
169
170 if (donelibheader)
171 return;
172 /*
173 * Copy filename over (obtained by preprocessor), carefully skipping
174 * over the quotes!
175 */
176
177 strncpy(filen, Filename + 1, strlen(Filename) - 2);
178 filen[strlen(Filename) - 2] = '\0';
179 if (1) {
180 char* ptr = filen;
181 if (!isalpha(*ptr) && *ptr != '_') {
182 memmove(ptr + 1, ptr, strlen(ptr) + 1);
183 *ptr = 'X';
184 }
185 while (*ptr) {
186 if (!isalnum(*ptr)) {
187 *ptr = '_';
188 }
189 ptr++;
190 }
191 /* Compiling a program */
192 outstr("\n\tMODULE\t");
193 if (strlen(filen) && strncmp(filen, "<stdin>", 7)) {
194 if ((segment = strrchr(filen, '/'))) /* Unix */
195 ++segment;
196 else if ((segment = strrchr(filen, '\\'))) /*DOG*/
197 segment++;
198 else if ((segment = strrchr(filen, ':'))) /*Amiga*/
199 segment++;
200 else
201 segment = filen;
202 debug_write_module();
203 outstr(segment);
204 } else {
205 /* This handles files produced by a filter cpp */
206 strcpy(filen, Filenorig);
207 if ((segment = strrchr(filen, '/'))) /* Unix */
208 ++segment;
209 else if ((segment = strrchr(filen, '\\'))) /*DOG*/
210 segment++;
211 else if ((segment = strrchr(filen, ':'))) /*Amiga*/
212 segment++;
213 else
214 segment = filen;
215 outstr("scp_"); /* alpha id incase tmpfile is numeric */
216 debug_write_module();
217 outstr(segment);
218 }
219 nl();
220 }
221 outstr("\n\n\tINCLUDE \"z80_crt0.hdr\"\n\n\n");
222 if (c_notaltreg) {
223 ol("EXTERN\tsaved_hl");
224 ol("EXTERN\tsaved_de");
225 }
226 donelibheader = 1;
227 }
228
229 /* Print any assembler stuff needed after all code */
gen_file_footer(void)230 void gen_file_footer(void)
231 {
232 outfmt("\n; --- End of Compilation ---\n");
233 }
234
235 /* Print out a name such that it won't annoy the assembler
236 * (by matching anything reserved, like opcodes.)
237 */
outname(const char * sname,char pref)238 void outname(const char* sname, char pref)
239 {
240 if (pref) {
241 outstr(Z80ASM_PREFIX);
242 }
243 outstr(sname);
244 }
245
246
reset_namespace()247 void reset_namespace()
248 {
249 current_nspace = NULL;
250 }
251
switch_namespace(char * name)252 static void switch_namespace(char *name)
253 {
254 namespace *ns;
255
256 if ( name == current_nspace || name == NULL ) {
257 return;
258 }
259 current_nspace = name;
260
261 if ( name != NULL ) {
262 ns = get_namespace(name);
263
264 if ( ns != NULL ) {
265 gen_call(-1, ns->bank_function->name, ns->bank_function);
266 }
267 }
268
269 }
270
271 /* Fetch a static memory cell into the primary register */
272 /* Can only have directly accessible things here...so should be
273 * able to just check for far to see if we need to pick up second
274 * bit of long pointer (check for type POINTER as well...
275 */
gen_load_static(SYMBOL * sym)276 void gen_load_static(SYMBOL* sym)
277 {
278 switch_namespace(sym->ctype->namespace);
279 if (sym->ctype->kind == KIND_CHAR) {
280 if ( (sym->ctype->isunsigned) == 0 ) {
281 #ifdef PREAPR00
282 ot("ld\ta,(");
283 outname(sym->name, dopref(sym));
284 outstr(")\n");
285 callrts("l_sxt");
286 #else
287 ot("ld\thl,");
288 outname(sym->name, dopref(sym));
289 nl();
290 callrts("l_gchar");
291 #endif
292
293 } else {
294 /* Unsigned char - new method - allows more optimizations! */
295 ot("ld\thl,");
296 outname(sym->name, dopref(sym));
297 nl();
298 ol("ld\tl,(hl)");
299 ol("ld\th,0");
300 }
301 #ifdef OLDLOADCHAR
302 ot("ld\ta,(");
303 outname(sym->name, dopref(sym));
304 outstr(")\n");
305 if (sym->ctype->isunsigned == 0 )
306 callrts("l_sxt");
307 else {
308 ol("ld\tl,a");
309 ol("ld\th,0");
310 }
311
312 #endif
313 } else if (sym->ctype->kind == KIND_DOUBLE && c_fp_size > 4 ) {
314 address(sym);
315 dcallrts("dload", KIND_DOUBLE);
316 } else if (sym->ctype->kind == KIND_LONGLONG ) {
317 address(sym);
318 callrts("l_i64_load");
319 } else if (sym->ctype->kind == KIND_LONG || (sym->ctype->kind == KIND_DOUBLE && c_fp_size == 4) || sym->ctype->kind == KIND_CPTR ) { // 4 byte doubles only
320 if ( IS_GBZ80() ) {
321 ot("ld\thl,");
322 outname(sym->name, dopref(sym));
323 outstr("\n");
324 callrts("l_glong");
325 } else {
326 ot("ld\thl,(");
327 outname(sym->name, dopref(sym));
328 outstr(")\n");
329 if ( !IS_808x() ) {
330 ot("ld\tde,(");
331 outname(sym->name, dopref(sym));
332 outstr("+2)\n");
333 } else {
334 swap();
335 ot("ld\thl,(");
336 outname(sym->name, dopref(sym));
337 outstr("+2)\n");
338 swap();
339 }
340 }
341 if (sym->ctype->kind == KIND_CPTR) {
342 ol("ld\td,0");
343 }
344 } else { /* KIND_INT */
345 if ( IS_GBZ80() ) {
346 ot("ld\thl,");
347 outname(sym->name, dopref(sym));
348 outstr("\n");
349 callrts("l_gint");
350 } else {
351 ot("ld\thl,(");
352 outname(sym->name, dopref(sym));
353 outstr(")\n");
354 }
355 }
356 }
357
358 /* Fetch the address of the specified symbol (from stack)
359 */
getloc(SYMBOL * sym,int off)360 int getloc(SYMBOL* sym, int off)
361 {
362 int offs;
363 offs = sym->offset.i - Zsp + off;
364 vconst(offs);
365 ol("add\thl,sp");
366 return (offs);
367 }
368
369 /* Store the primary register into the specified */
370 /* static memory cell */
gen_store_static(SYMBOL * sym)371 void gen_store_static(SYMBOL* sym)
372 {
373 switch_namespace(sym->ctype->namespace);
374 if (sym->ctype->kind == KIND_DOUBLE && c_fp_size > 4 ) {
375 address(sym);
376 dcallrts("dstore", KIND_DOUBLE);
377 } else if (sym->ctype->kind == KIND_CHAR) {
378 ol("ld\ta,l");
379 ot("ld\t(");
380 outname(sym->name, dopref(sym));
381 outstr("),a\n");
382 } else if (sym->ctype->kind == KIND_LONGLONG) {
383 ot("ld\tbc,");
384 outname(sym->name, dopref(sym));
385 outstr("\n");
386 callrts("l_i64_store");
387 } else if (sym->ctype->kind == KIND_LONG || (sym->ctype->kind == KIND_DOUBLE && c_fp_size == 4) ) { // 4 byte doubles
388 if ( IS_GBZ80() ) {
389 ot("ld\tbc,");
390 outname(sym->name, dopref(sym));
391 outstr("\n");
392 callrts("l_plong");
393 } else {
394 ot("ld\t(");
395 outname(sym->name, dopref(sym));
396 outstr("),hl\n");
397 if ( !IS_808x() ) {
398 ot("ld\t(");
399 outname(sym->name, dopref(sym));
400 outstr("+2),de\n");
401 } else {
402 swap();
403 ot("ld\t(");
404 outname(sym->name, dopref(sym));
405 outstr("+2),hl\n");
406 swap();
407 }
408 }
409 } else if (sym->ctype->kind == KIND_CPTR) {
410 if ( IS_GBZ80() ) {
411 ot("ld\tbc,");
412 outname(sym->name, dopref(sym));
413 outstr("\n");
414 callrts("l_putptr");
415 } else {
416 ot("ld\t(");
417 outname(sym->name, dopref(sym));
418 outstr("),hl\n");
419 ol("ld\ta,e");
420 ot("ld\t(");
421 outname(sym->name, dopref(sym));
422 outstr("+2),a\n");
423 }
424 } else {
425 if ( IS_GBZ80() ) {
426 ot("ld\tde,");
427 outname(sym->name, dopref(sym));
428 outstr("\n");
429 callrts("l_pint");
430 } else {
431 ot("ld\t(");
432 outname(sym->name, dopref(sym));
433 outstr("),hl\n");
434 }
435 }
436 }
437
438 /*
439 * Store type at TOS - used for initialising auto vars
440 */
gen_store_to_tos(Kind typeobj)441 void gen_store_to_tos(Kind typeobj)
442 {
443 switch (typeobj) {
444 case KIND_LONGLONG:
445 llpush();
446 return;
447 case KIND_LONG:
448 lpush();
449 return;
450 case KIND_CHAR:
451 ol("dec\tsp");
452 ol("ld\ta,l");
453 pop("hl");
454 ol("ld\tl,a");
455 push("hl");
456 Zsp--;
457 return;
458 case KIND_DOUBLE:
459 gen_push_float(typeobj);
460 return;
461 /* KIND_CPTR..untested */
462 case KIND_CPTR:
463 ol("dec\tsp");
464 ol("ld\ta,e");
465 pop("de"); /* pop de */
466 ol("ld\te,a");
467 push("de");
468 push("hl");
469 Zsp--;
470 return;
471 default:
472 push("hl");
473 return;
474 }
475 }
476
477 /*
478 * Store the object at the frame position marked by offset
479 * We already know that it's in range
480 */
481
482 #ifdef USEFRAME
PutFrame(char typeobj,int offset)483 void PutFrame(char typeobj, int offset)
484 {
485 Type* ctype;
486 char flags;
487
488 ctype = retrstk(&flags); /* Not needed but.. */
489 switch (typeobj) {
490 case KIND_CHAR:
491 ot("ld\t");
492 OutIndex(offset);
493 outstr(",l\n");
494 break;
495 case KIND_INT:
496 case KIND_PTR:
497 ot("ld\t");
498 OutIndex(offset);
499 outstr(",l\n");
500 ot("ld\t");
501 OutIndex(offset + 1);
502 outstr(",h\n");
503 break;
504 case KIND_CPTR:
505 case KIND_LONG:
506 ot("ld\t");
507 OutIndex(offset);
508 outstr(",l\n");
509 ot("ld\t");
510 OutIndex(offset + 1);
511 outstr(",h\n");
512 ot("ld\t");
513 OutIndex(offset + 2);
514 outstr(",e\n");
515 ot("ld\t");
516 if (typeobj == KIND_LONG) {
517 OutIndex(offset + 3);
518 outstr(",d\n");
519 }
520 }
521 }
522 #endif
523
524 /* Store the specified object type in the primary register */
525 /* at the address on the top of the stack */
putstk(LVALUE * lval)526 void putstk(LVALUE *lval)
527 {
528 char flags = 0;
529 Type *ctype;
530 Kind typeobj = lval->indirect_kind;
531
532 //outfmt("; %s type=%d val_type=%d indirect=%d\n", lval->ltype->name, lval->type, lval->val_type, lval->indirect_kind);
533 /* Store via long pointer... */
534 ctype = retrstk(&flags);
535 if ( ctype != NULL ) {
536 switch_namespace(ctype->namespace);
537 }
538 //outfmt(";Restore %p flags %02d\n",ptr, flags);
539 if (flags & FARACC) {
540 /* exx pop hl, pop de, exx */
541 ol("exx");
542 pop("hl");
543 pop("de");
544 ol("exx");
545 switch (typeobj) {
546 case KIND_DOUBLE:
547 dcallrts("lp_pdoub", KIND_DOUBLE);
548 break;
549 case KIND_CPTR:
550 callrts("lp_pptr");
551 break;
552 case KIND_LONGLONG:
553 callrts("lp_i64_load");
554 break;
555 case KIND_LONG:
556 callrts("lp_plong");
557 break;
558 case KIND_CHAR:
559 callrts("lp_pchar");
560 break;
561 case KIND_STRUCT:
562 warningfmt("incompatible-pointer-types","Cannot assign a __far struct");
563 default:
564 callrts("lp_pint");
565 }
566 return;
567 }
568
569 if ( ctype->bit_size ) {
570 int bit_offset = lval->ltype->bit_offset;
571 int doinc = 0;
572
573 if ( bit_offset >= 8 ) {
574 bit_offset -= 8;
575 doinc = 1;
576 }
577
578 if ( lval->ltype->bit_size + bit_offset <= 8 ) {
579 int i;
580 pop("de"); // de address
581 if ( doinc ) {
582 ol("inc\tde");
583 }
584
585 ol("ld\ta,l");
586 if ( bit_offset >= 4) {
587 for ( i = 0; i < (8 - bit_offset); i++ ) {
588 ol("rrca");
589 }
590 } else {
591 for ( i = 0; i < bit_offset; i++ ) {
592 ol("rlca");
593 }
594 }
595 outfmt("\tand\t%d\n",((1 << lval->ltype->bit_size) - 1) << bit_offset);
596 ol("ld\tl,a");
597 ol("ld\ta,(de)");
598 outfmt("\tand\t%d\n",0xff - (((1 << lval->ltype->bit_size) - 1) << bit_offset));
599 ol("or\tl");
600 ol("ld\t(de),a");
601 } else {
602 // hl = value, lets shift into the right place
603 asl_const(lval, lval->ltype->bit_offset);
604 zand_const(lval,((1 << lval->ltype->bit_size) - 1) << bit_offset);
605 pop("de"); // de = destination address
606 ol("ld\ta,(de)");
607 outfmt("\tand\t%d\n",(0xffff - (((1 << lval->ltype->bit_size) - 1) << bit_offset)) % 256);
608 ol("or\tl");
609 ol("ld\t(de),a");
610 ol("inc\tde");
611 ol("ld\ta,(de)");
612 outfmt("\tand\t%d\n",(0xffff - (((1 << lval->ltype->bit_size) - 1) << bit_offset)) / 256);
613 ol("or\th");
614 ol("ld\t(de),a");
615 }
616 return;
617 }
618
619
620 switch (typeobj) {
621 case KIND_DOUBLE:
622 if ( c_fp_size > 4) {
623 pop("hl");
624 dcallrts("dstore", KIND_DOUBLE);
625 } else {
626 pop("bc");
627 dcallrts("dstore", KIND_DOUBLE);
628 }
629 break;
630 case KIND_CPTR:
631 pop("bc");
632 callrts("l_putptr");
633 break;
634 case KIND_LONGLONG:
635 pop("bc");
636 callrts("l_i64_store");
637 break;
638 case KIND_LONG:
639 pop("bc");
640 callrts("l_plong");
641 break;
642 case KIND_CHAR:
643 pop("de");
644 ol("ld\ta,l");
645 ol("ld\t(de),a");
646 break;
647 case KIND_STRUCT:
648 pop("de");
649 outfmt("\tld\tbc,%d\n",lval->ltype->size);
650 ol("ldir");
651 break;
652 default:
653 pop("de");
654 callrts("l_pint");
655 }
656 }
657
658 /* store a two byte object in the primary register at TOS */
puttos(void)659 void puttos(void)
660 {
661 #ifdef USEFRAME
662 if (c_framepointer_is_ix != -1) {
663 ot("ld\t");
664 OutIndex(0);
665 outstr(",l\n");
666 ot("ld\t");
667 OutIndex(1);
668 outstr(",h\n");
669 return;
670 }
671 #endif
672 ol("pop\tbc");
673 ol("push\thl");
674 }
675
676 /* store a two byte object in the primary register at 2nd TOS */
put2tos(void)677 void put2tos(void)
678 {
679 #ifdef USEFRAME
680 if (c_framepointer_is_ix != -1) {
681 ot("ld\t");
682 OutIndex(2);
683 outstr(",l\n");
684 ot("ld\t");
685 OutIndex(3);
686 outstr(",h\n");
687 return;
688 }
689 #endif
690 ol("pop\tde");
691 puttos();
692 ol("push\tde");
693 }
694
695 /*
696 * loadargc - load accumulator with number of words of stack
697 * if n=0 then emit xor a instead of ld a,0
698 * (this is picked up by the optimizer, but even so)
699 */
loadargc(int n)700 static void loadargc(int n)
701 {
702 n >>= 1;
703 loada(n);
704 }
705
loada(int n)706 static void loada(int n)
707 {
708 if (n) {
709 ot("ld\ta,");
710 outdec(n);
711 nl();
712 } else
713 ol("xor\ta");
714 }
715
716 // Read a bitfield from (hl)
get_bitfield(LVALUE * lval)717 void get_bitfield(LVALUE *lval)
718 {
719 int bit_offset = lval->ltype->bit_offset;
720
721 if ( bit_offset >= 8 ) {
722 bit_offset -= 8;
723 ol("inc\thl");
724 }
725
726 if ( lval->ltype->bit_size + bit_offset <= 8 ) {
727 int i;
728 ol("ld\ta,(hl)");
729 // Shift left as necessary
730 if ( bit_offset >= 4) {
731 for ( i = 0; i < (8 - bit_offset); i++ ) {
732 ol("rlca");
733 }
734 } else {
735 for ( i = 0; i < bit_offset; i++ ) {
736 ol("rrca");
737 }
738 }
739 if ( lval->ltype->bit_size % 8 ) {
740 outfmt("\tand\t%d\n",(1 << lval->ltype->bit_size) - 1);
741 }
742 if ( lval->ltype->isunsigned == 0 ) {
743 // We need to do some bit extension here
744 if ( lval->ltype->bit_size % 8 ) {
745 if ( IS_808x() ) {
746 ol("ld\tl,a");
747 outfmt("\tand\t%d\n",(1 << (lval->ltype->bit_size - 1)));
748 ol("ld\ta,l");
749 ol("jp\tz,ASMPC+5");
750 } else {
751 outfmt("\tbit\t%d,a\n",lval->ltype->bit_size - 1);
752 ol("jr\tz,ASMPC+4");
753 }
754 outfmt("\tor\t%d\n",0xff - ((1 << lval->ltype->bit_size) - 1));
755 }
756 ol("ld\tl,a");
757 ol("rlca");
758 ol("sbc\ta,a");
759 ol("ld\th,a");
760 } else {
761 ol("ld\tl,a");
762 ol("ld\th,0");
763 }
764 } else {
765 // This is a value that starts and bit 0 and then carries on into the next byte
766 ol("ld\te,(hl)");
767 ol("inc\thl");
768 ol("ld\ta,(hl)");
769 outfmt("\tand\t%d\n",(1 << (lval->ltype->bit_size - 8)) - 1);
770 if ( lval->ltype->isunsigned == 0 ) {
771 if ( IS_808x() ) {
772 ol("ld\th,a");
773 outfmt("\tand\t%d\n",(1 << (lval->ltype->bit_size - 8 - 1)));
774 ol("ld\ta,h");
775 ol("jp\tz,ASMPC+5");
776 } else {
777 outfmt("\tbit\t%d,a\n",lval->ltype->bit_size - 8 - 1);
778 ol("jr\tz,ASMPC+4");
779 }
780 outfmt("\tor\t%d\n",0xff - ((1 << (lval->ltype->bit_size - 8)) - 1));
781 }
782 ol("ld\th,a");
783 ol("ld\tl,e");
784 }
785 }
786
787
788 /* Fetch the specified object type indirect through the */
789 /* primary register into the primary register */
gen_load_indirect(LVALUE * lval)790 void gen_load_indirect(LVALUE* lval)
791 {
792 char sign;
793 char flags;
794 Kind typeobj;
795
796 typeobj = lval->indirect_kind;
797 flags = lval->flags;
798
799 sign = lval->ltype->isunsigned;
800
801 /* Fetch from far pointer */
802 if (flags & FARACC) { /* Access via far method */
803 switch (typeobj) {
804 case KIND_CHAR:
805 callrts("lp_gchar");
806 if (!sign)
807 callrts("l_sxt");
808 /* else ol("ld\th,0"); */
809 break;
810 case KIND_CPTR:
811 callrts("lp_gptr");
812 break;
813 case KIND_LONGLONG:
814 callrts("lp_glonglong");
815 break;
816 case KIND_LONG:
817 callrts("lp_glong");
818 break;
819 case KIND_DOUBLE:
820 dcallrts("lp_gdoub",KIND_DOUBLE);
821 break;
822 case KIND_STRUCT:
823 warningfmt("incompatible-pointer-types","Cannot retrieve a struct via __far");
824 default:
825 callrts("lp_gint");
826 }
827 return;
828 }
829
830 if ( lval->ltype->bit_size ) {
831 get_bitfield(lval);
832 return;
833 }
834
835 switch (typeobj) {
836 case KIND_CHAR:
837 if (!sign) {
838 #ifdef PREAPR00
839 ol("ld\ta,(hl)");
840 callrts("l_sxt");
841 #else
842 callrts("l_gchar");
843 #endif
844 } else {
845 ol("ld\tl,(hl)");
846 ol("ld\th,0");
847 }
848 break;
849 case KIND_CPTR:
850 callrts("l_getptr");
851 break;
852 case KIND_LONGLONG:
853 callrts("l_i64_load");
854 break;
855 case KIND_LONG:
856 callrts("l_glong");
857 break;
858 case KIND_DOUBLE:
859 dcallrts("dload",KIND_DOUBLE);
860 break;
861 case KIND_STRUCT:
862 break;
863 default:
864 ot("call\tl_gint\t;");
865 #ifdef USEFRAME
866 if (c_framepointer_is_ix != -1 && CheckOffset(lval->offset)) {
867 OutIndex(lval->offset);
868 }
869 #endif
870 nl();
871 }
872 }
873
874 /* Swap the primary and secondary registers */
swap(void)875 static void swap(void)
876 {
877 if ( IS_GBZ80() ) {
878 // Crude emulation - we can probably do better on a case by case basis
879 ol("push\thl");
880 ol("ld\tl,e");
881 ol("ld\th,d");
882 ol("pop\tde");
883 } else {
884 ol("ex\tde,hl");
885 }
886 }
887
888 /* Print partial instruction to get an immediate value */
889 /* into the primary register */
immed(void)890 void immed(void)
891 {
892 ot("ld\thl,");
893 }
894
895 /* Print partial instruction to get an immediate value */
896 /* into the secondary register */
immed2(void)897 static void immed2(void)
898 {
899 ot("ld\tde,");
900 }
901
902 /* Partial instruction to access literal */
immedlit(int lab,int offs)903 void immedlit(int lab, int offs)
904 {
905 outfmt("\tld\thl,i_%d+%d",lab,offs);
906 }
907
908 /* Push long onto stack */
lpush(void)909 void lpush(void)
910 {
911 push("de");
912 push("hl");
913 }
914
llpush(void)915 void llpush(void)
916 {
917 callrts("l_i64_push");
918 Zsp -= 8;
919 }
920
gen_push_primary(LVALUE * lval)921 void gen_push_primary(LVALUE *lval)
922 {
923 switch ( lval->val_type ) {
924 case KIND_DOUBLE:
925 case KIND_FLOAT16:
926 gen_push_float(lval->val_type);
927 break;
928 case KIND_LONGLONG:
929 llpush();
930 break;
931 case KIND_LONG:
932 case KIND_CPTR:
933 lpush();
934 break;
935 default:
936 zpush();
937 }
938 }
939
940 /* Push the primary register onto the stack */
zpush(void)941 void zpush(void)
942 {
943 push("hl");
944 }
945
946 /* Push the primary floating point register onto the stack */
947
gen_push_float(Kind typeToPush)948 void gen_push_float(Kind typeToPush)
949 {
950 if ( typeToPush == KIND_FLOAT16 ) {
951 push("hl");
952 } else if ( c_fp_size == 4 ) {
953 push("de");
954 push("hl");
955 } else {
956 dcallrts("fpush",KIND_DOUBLE);
957 Zsp -= c_fp_size;
958 }
959 }
960
961 /* Push an argument for a function pointer call: regular or far pointer */
gen_push_function_argument(Kind expr,Type * type,int push_sdccchar)962 int gen_push_function_argument(Kind expr, Type *type, int push_sdccchar)
963 {
964 if (expr == KIND_DOUBLE) {
965 gen_push_float(expr);
966 return type_double->size;
967 } else if ( expr == KIND_LONGLONG ) {
968 llpush();
969 return 8;
970 } else if (expr == KIND_LONG || expr == KIND_CPTR) {
971 lpush();
972 return 4;
973 } else if ( expr == KIND_CHAR && push_sdccchar ) {
974 ol("ld\tb,l");
975 ol("push\tbc");
976 ol("inc\tsp");
977 Zsp--;
978 return 1;
979 } else if (expr == KIND_STRUCT) {
980 swap(); /* de = stack address */
981 vconst(-type->size);
982 ol("add\thl,sp");
983 ol("ld\tsp,hl");
984 Zsp -= type->size;
985 swap();
986 outfmt("\tld\tbc,%d\n",type->size);
987 ol("ldir");
988 return type->size;
989 }
990 // Default push the word
991 push("hl");
992 return 2;
993 }
994
995 /* Push an argument for a function pointer call
996 *
997 * \return The stack offset
998 *
999 * For int/long sized parameters, we need to leave the parameter in the registers for the last
1000 * argument
1001 */
push_function_argument_fnptr(Kind expr,Type * type,Type * functype,int push_sdccchar,int is_last_argument)1002 int push_function_argument_fnptr(Kind expr, Type *type, Type *functype, int push_sdccchar, int is_last_argument)
1003 {
1004 if (expr == KIND_LONG || expr == KIND_CPTR || ( c_fp_size == 4 && expr == KIND_DOUBLE)) {
1005 if (is_last_argument == 0 || (functype->flags & FASTCALL) == 0 ) {
1006 swap(); /* MSW -> hl */
1007 ol("ex\t(sp),hl"); /* MSW -> stack, addr -> hl */
1008 push("de"); /* LSW -> stack, addr = hl */
1009 return 4;
1010 }
1011 } else if ( expr == KIND_LONGLONG ) {
1012 if (is_last_argument == 0 || (functype->flags & FASTCALL) == 0 ) {
1013 callrts("l_i64_push_under_int");
1014 Zsp -= 6;
1015 return 8;
1016 }
1017 } else if (expr == KIND_DOUBLE ) {
1018 if (is_last_argument == 0 || (functype->flags & FASTCALL) == 0 ) {
1019 dpush_under(KIND_INT);
1020 pop("hl");
1021 return c_fp_size;
1022 }
1023 } else if (expr == KIND_STRUCT ) {
1024 // 13 bytes
1025 swap(); // de = address of struct
1026 ol("pop\tbc"); // return address
1027 vconst(-type->size);
1028 ol("add\thl,sp");
1029 ol("ld\tsp,hl");
1030 ol("push\tbc");
1031 Zsp -= type->size;
1032 swap();
1033 outfmt("\tld\tbc,%d\n",type->size);
1034 ol("ldir");
1035 pop("hl");
1036 return type->size;
1037 } else if (is_last_argument == 0 || (functype->flags & FASTCALL) == 0 ) {
1038 if ( IS_GBZ80() ) {
1039 ol("ld\td,h");
1040 ol("ld\te,l");
1041 ol("pop\thl");
1042 ol("push\tde");
1043 } else {
1044 ol("ex\t(sp),hl");
1045 }
1046 return 2;
1047 }
1048 return 0;
1049 }
1050
1051
1052
1053 /* Push the primary floating point register, preserving the top value */
dpush_under(Kind val_type)1054 void dpush_under(Kind val_type)
1055 {
1056 // Only called for KIND_DOUBLE
1057 if ( val_type == KIND_LONG || val_type == KIND_CPTR ) {
1058 if ( c_fp_size == 4 ) {
1059 ol("pop\tbc"); // addr2 -> bc
1060 swap(); /* MSW -> hl */
1061 ol("ex\t(sp),hl"); /* MSW -> stack, addr1 -> hl */
1062 push("de"); /* LSW -> stack, addr1 = hl */
1063 push("hl"); // addr -> stack
1064 ol("push\tbc"); // addr2 -> stack
1065 } else {
1066 dcallrts("dpush_under_long",KIND_DOUBLE);
1067 Zsp -= c_fp_size;
1068 }
1069 } else {
1070 if ( c_fp_size == 4 ) {
1071 swap(); /* MSW -> hl */
1072 ol("ex\t(sp),hl"); /* MSW -> stack, addr -> hl */
1073 push("de"); /* LSW -> stack, addr = hl */
1074 push("hl");
1075 } else if (c_fp_size == 2 ) {
1076 ol("ex\t(sp),hl"); /* float -> stack, addr -> hl */
1077 push("hl");
1078 } else {
1079 dcallrts("dpush_under_int",KIND_DOUBLE);
1080 Zsp -= c_fp_size;
1081 }
1082 }
1083 }
1084
1085
push(const char * reg)1086 static void push(const char *reg)
1087 {
1088 outfmt("\tpush\t%s\n",reg);
1089 Zsp -= 2;
1090 }
1091
pop(const char * reg)1092 static void pop(const char *reg)
1093 {
1094 outfmt("\tpop\t%s\n",reg);
1095 Zsp += 2;
1096 }
1097
1098
1099 /* Pop the top of the stack into the secondary register */
zpop(void)1100 void zpop(void)
1101 {
1102 pop("de");
1103 }
1104
1105 /* Output the call op code */
gen_call(int arg_count,const char * name,SYMBOL * sym)1106 void gen_call(int arg_count, const char *name, SYMBOL *sym)
1107 {
1108 if (sym->ctype->return_type->kind == KIND_LONGLONG) {
1109 ol("ld\tbc,__i64_acc");
1110 push("bc");
1111 }
1112 if (arg_count != -1 ) {
1113 loadargc(arg_count);
1114 }
1115 ot("call\t"); outname(name, dopref(sym)); nl();
1116 }
1117
gen_shortcall(Type * functype,int rst,int value)1118 void gen_shortcall(Type *functype, int rst, int value)
1119 {
1120 if ((functype->flags & SHORTCALL_HL) == SHORTCALL_HL) {
1121 if ((functype->flags & FASTCALL) == FASTCALL) {
1122 // preserve HL from FASTCALL into BC because hl is going to erase it
1123 outfmt("\tld bc,\thl\n");
1124 }
1125 vconst(value);
1126 outfmt("\trst\t%d\n", rst);
1127 } else {
1128 if (functype->return_type->kind == KIND_LONGLONG) {
1129 ol("ld\tbc,__i64_acc");
1130 push("bc");
1131 }
1132 outfmt("\trst\t%d\n",rst);
1133 outfmt("\t%s\t%d\n", value < 0x100 ? "defb" : "defw", value);
1134 }
1135 }
1136
gen_hl_call(Type * functype,int module,int address)1137 void gen_hl_call(Type *functype, int module, int address)
1138 {
1139 if ((functype->flags & FASTCALL) == FASTCALL) {
1140 // preserve HL from FASTCALL into BC because hl is going to erase it
1141 outfmt("\tld bc,\thl\n");
1142 }
1143 vconst(module);
1144 outfmt("\tcall\t%d\n", address);
1145 }
1146
gen_bankedcall(SYMBOL * sym)1147 void gen_bankedcall(SYMBOL *sym)
1148 {
1149 if (sym->ctype->return_type->kind == KIND_LONGLONG) {
1150 ol("ld\tbc,__i64_acc");
1151 push("bc");
1152 }
1153 ol("call\tbanked_call");
1154 ot("defq\t"); outname(sym->name, dopref(sym)); nl();
1155 }
1156
1157 /* djm (move this!) Decide whether to print a prefix or not
1158 * This uses new flags bit LIBRARY
1159 */
1160
dopref(SYMBOL * sym)1161 char dopref(SYMBOL* sym)
1162 {
1163 if (sym->ctype->flags & LIBRARY && (sym->ctype->kind == KIND_FUNC ) ) { // || sym->ident == FUNCTIONP)) {
1164 return (0);
1165 }
1166 return (1);
1167 }
1168
1169 /* Call a run-time library routine */
callrts(char * sname)1170 void callrts(char* sname)
1171 {
1172 const char *func_name = map_library_routine(sname, KIND_VOID);
1173 ot("call\t");
1174 outstr(func_name);
1175 nl();
1176 }
1177
dcallrts(char * sname,Kind to)1178 void dcallrts(char* sname, Kind to)
1179 {
1180 const char *func_name = map_library_routine(sname, to);
1181 ot("call\t");
1182 outstr(func_name);
1183 nl();
1184 }
1185
1186
1187 /*
1188 * Perform subroutine call to value on top of stack
1189 * Put arg count in A in case subroutine needs it
1190 *
1191 * Returns an "nargs" adjustment to handle fastcall
1192 */
callstk(Type * type,int n,int isfarptr,int last_argument_size)1193 int callstk(Type *type, int n, int isfarptr, int last_argument_size)
1194 {
1195 if ( isfarptr ) {
1196 // The function address is on the stack at +n
1197 if ( n > 0 ) {
1198 vconst(n);
1199 ol("add\thl,sp");
1200 ol("ld\te,(hl)");
1201 ol("inc\thl");
1202 ol("ld\td,(hl)");
1203 ol("inc\thl");
1204 ol("ld\tl,(hl)");
1205 ol("ex\tde,hl");
1206 }
1207 loadargc(n);
1208 callrts("l_farcall");
1209 } else if ( type->flags & FASTCALL && last_argument_size <= 4 ) {
1210 int ret = 0;
1211 int label = getlabel();
1212
1213 // TOS = address, dehl = parameter (or in memory)
1214 if ( last_argument_size == 2 ) {
1215 ret -= 4;
1216 }
1217
1218 ol("pop\taf"); // TODO: 8080/gbz80 doesn't work here
1219 if (type->return_type->kind == KIND_LONGLONG) {
1220 ol("ld\tbc,__i64_acc");
1221 push("bc");
1222 }
1223 outstr("\tld\tbc,"); printlabel(label); nl(); // bc = return address
1224 ol("push\tbc");
1225 ol("push\taf");
1226 Zsp += 2;
1227
1228 ol("ret");
1229 postlabel(label);
1230 return ret;
1231 } else {
1232 // Non __z88dk_fastcall function pointers and those qwhich have a
1233 // fastcall argument that's stored in memory
1234 if ( type->funcattrs.hasva )
1235 loadargc(n);
1236
1237 if (type->return_type->kind == KIND_LONGLONG) {
1238 ol("ld\tbc,__i64_acc");
1239 push("bc");
1240 }
1241 callrts("l_jphl");
1242 }
1243 return 0;
1244 }
1245
gen_save_pointer(LVALUE * lval)1246 void gen_save_pointer(LVALUE *lval)
1247 {
1248 if (lval->flags & FARACC)
1249 lpush();
1250 else
1251 zpush();
1252 }
1253
1254
1255 /* Jump to specified internal label number */
gen_jp_label(int label)1256 void gen_jp_label(int label)
1257 {
1258 opjump("", label);
1259 }
1260
1261 /* Jump relative to specified internal label */
jumpr(int label)1262 void jumpr(int label)
1263 {
1264 opjumpr("", label);
1265 }
1266
1267 /*
1268 * Output the jump code, with conditions as needed
1269 */
1270
opjump(char * cc,int label)1271 void opjump(char* cc, int label)
1272 {
1273 ot("jp\t");
1274 outstr(cc);
1275 printlabel(label);
1276 nl();
1277 }
1278
opjumpr(char * cc,int label)1279 void opjumpr(char* cc, int label)
1280 {
1281 ot("jr\t");
1282 outstr(cc);
1283 printlabel(label);
1284 nl();
1285 }
1286
jumpc(int label)1287 void jumpc(int label)
1288 {
1289 opjump("c,", label);
1290 }
1291
jumpnc(int label)1292 void jumpnc(int label)
1293 {
1294 opjump("nc,", label);
1295 }
1296
setcond(int val)1297 static void setcond(int val)
1298 {
1299 if (val == 1)
1300 ol("scf");
1301 else
1302 ol("and\ta");
1303 }
1304
1305 /* Test the primary register and jump if false to label */
testjump(LVALUE * lval,int label)1306 void testjump(LVALUE* lval, int label)
1307 {
1308 Kind type;
1309
1310 ol("ld\ta,h");
1311 ol("or\tl");
1312
1313 type = lval->val_type;
1314 if (lval->binop == NULL)
1315 type = lval->val_type;
1316
1317 if (type == KIND_LONG && check_lastop_was_comparison(lval)) {
1318 ol("or\td");
1319 ol("or\te");
1320 } else if (type == KIND_CPTR && check_lastop_was_comparison(lval)) {
1321 ol("or\te");
1322 } else if ( type == KIND_LONGLONG && check_lastop_was_comparison(lval)) {
1323 ol("or\td");
1324 ol("or\te");
1325 ol("exx");
1326 ol("or\th");
1327 ol("or\tl");
1328 ol("or\td");
1329 ol("or\te");
1330 ol("exx");
1331 }
1332 opjump("z,", label);
1333 }
1334
1335
1336 /* Print pseudo-op to define a byte */
defbyte(void)1337 void defbyte(void)
1338 {
1339 ot("defb\t");
1340 }
1341
1342 /*Print pseudo-op to define storage */
defstorage(void)1343 void defstorage(void)
1344 {
1345 ot("defs\t");
1346 }
1347
1348 /* Print pseudo-op to define a word */
defword(void)1349 void defword(void)
1350 {
1351 ot("defw\t");
1352 }
1353
1354 /* Print pseudo-op to dump a long */
deflong(void)1355 void deflong(void)
1356 {
1357 ot("defq\t");
1358 }
1359
1360 /* Print pseudo-op to define a string */
defmesg(void)1361 void defmesg(void)
1362 {
1363 ot("defm\t\"");
1364 }
1365
1366 /* Point to following object */
point(void)1367 void point(void)
1368 {
1369 ol("defw\tASMPC+2");
1370 }
1371
1372
1373 /*
1374 * \brief Generate the leave state for a function
1375 *
1376 * \param vartype The type of variable we're leaving with
1377 * \param type 1=c, 2=nc, 0=no carry state
1378 * \param incritical - We're in a critical section, restore interrupts
1379 */
gen_leave_function(Kind vartype,char type,int incritical)1380 void gen_leave_function(Kind vartype, char type, int incritical)
1381 {
1382 int savesp;
1383 Kind save = vartype;
1384 int callee_cleanup = (currfn->ctype->flags & CALLEE) && (stackargs > 2);
1385
1386 if ( (currfn->flags & NAKED) == NAKED ) {
1387 return;
1388 }
1389
1390 if (vartype == KIND_CPTR) /* they are the same in any case! */
1391 vartype = KIND_LONG;
1392 else if ( vartype == KIND_DOUBLE ) {
1393 if ( c_fp_size == 4 ) {
1394 vartype = KIND_LONG;
1395 } else {
1396 vartype = KIND_NONE;
1397 save = NO;
1398 }
1399 } else if (vartype == KIND_FLOAT16 ) {
1400 vartype = KIND_INT;
1401 } else if (vartype == KIND_LONGLONG) {
1402 vartype = KIND_NONE;
1403 }
1404 modstk(0, vartype, NO,YES);
1405
1406 if (callee_cleanup) {
1407 int bcused = 0;
1408
1409 // TODO: LONGLONG stuffed pointer
1410
1411 savesp = Zsp;
1412 Zsp = -stackargs;
1413
1414 if ( save == KIND_LONGLONG) {
1415 pop("de");
1416 pop("hl");
1417 push("de");
1418 callrts("l_i64_copy");
1419 }
1420
1421 if ( c_notaltreg && ( vartype != KIND_NONE && vartype != KIND_DOUBLE && vartype != KIND_LONGLONG) && abs(Zsp) >= 11 ) {
1422 // 8080, save hl, pop return int hl
1423 ol("ld\t(saved_hl),hl");
1424 pop("hl");
1425 } else {
1426 // Pop return address into bc
1427 pop("bc");
1428 bcused = 1;
1429 }
1430
1431 if ( Zsp > 0 ) {
1432 errorfmt("Internal error: Cannot cleanup function by lowering sp: Zsp=%d",1,Zsp);
1433 }
1434 modstk(0, vartype, NO, !bcused);
1435
1436 if ( bcused ) {
1437 ol("push\tbc");
1438 } else {
1439 push("hl");
1440 ol("ld\thl,(saved_hl)");
1441 }
1442 Zsp = savesp;
1443 }
1444 gen_pop_frame(); /* Restore previous frame pointer */
1445
1446
1447 if ( (currfn->flags & INTERRUPT) == INTERRUPT ) {
1448 gen_interrupt_leave(currfn);
1449 return;
1450 }
1451
1452 /* Naked has already returned */
1453 if ( (currfn->flags & CRITICAL) == CRITICAL || incritical) {
1454 gen_critical_leave();
1455 }
1456
1457 if ( !callee_cleanup && save == KIND_LONGLONG ) {
1458 pop("de");
1459 pop("hl");
1460 push("hl");
1461 push("de");
1462 callrts("l_i64_copy");
1463 }
1464
1465
1466 if (type)
1467 setcond(type);
1468 ol("ret"); nl(); nl(); /* and exit function */
1469 }
1470
1471
gen_restore_frame_after_call(int offset,Kind save,int saveaf,int usebc)1472 int gen_restore_frame_after_call(int offset, Kind save, int saveaf, int usebc)
1473 {
1474 return modstk(Zsp + offset, save, saveaf, usebc);
1475 }
1476
1477 /* Modify the stack pointer to the new value indicated
1478 * \param newsp - Where we need to be
1479 * \param save - NO or the variable type that we need to preserve
1480 * \param saveaf - Whether we should save af
1481 *
1482 * \return newsp value
1483 */
modstk(int newsp,Kind save,int saveaf,int usebc)1484 int modstk(int newsp, Kind save, int saveaf, int usebc)
1485 {
1486 int k, flag = NO;
1487
1488 k = newsp - Zsp;
1489
1490 if (k == 0)
1491 return newsp;
1492 if ( (c_cpu & (CPU_GBZ80|CPU_RABBIT)) && abs(k) > 1 && abs(k) <= 127 ) {
1493 outstr("\tadd\tsp,"); outdec(k); nl();
1494 return newsp;
1495 }
1496
1497 #ifdef USEFRAME
1498 if (c_framepointer_is_ix != -1) {
1499 if ( saveaf ) {
1500 if ( c_noaltreg ) {
1501 push("af");
1502 pop("bc");
1503 } else {
1504 ol("ex\taf,af");
1505 }
1506 }
1507 outfmt("\tld\t%s,%d\n",FRAME_REGISTER, k);
1508 outfmt("\tadd\t%s,sp\n", FRAME_REG);
1509 outfmt("\tld\tsp,%s\n",FRAME_REGISTER);
1510 if ( saveaf ) {
1511 if ( c_noaltreg ) {
1512 ol("push\tbc");
1513 Zsp -= 2;
1514 pop("af");
1515 } else {
1516 ol("ex\taf,af");
1517 }
1518 }
1519 return newsp;
1520 }
1521 #endif
1522
1523 // Handle short cases
1524 if (k > 0) {
1525 if (k < 11) {
1526 if (k & 1) {
1527 ol("inc\tsp");
1528 --k;
1529 }
1530 while (k) {
1531 if (usebc) {
1532 ol("pop\tbc");
1533 } else {
1534 ol("pop\taf");
1535 }
1536 k -= 2;
1537 }
1538 return newsp;
1539 }
1540 } else if (k < 0) {
1541 if (k > -11) {
1542 if (k & 1) {
1543 flag = YES;
1544 ++k;
1545 }
1546 while (k) {
1547 ol("push\tbc");
1548 k += 2;
1549 }
1550 if (flag)
1551 ol("dec\tsp");
1552 return newsp;
1553 }
1554 }
1555
1556 // It's a case where modifying sp via hl is easiest
1557 if (save == KIND_CPTR) /* they are the same in any case! */
1558 save = KIND_LONG;
1559 else if ( save == KIND_DOUBLE ) {
1560 if ( c_fp_size == 4 ) {
1561 save = KIND_LONG;
1562 }
1563 // For a 6/8 byte double the value is safely in the exx set or in FA
1564 } else if ( save == KIND_FLOAT16 ) {
1565 save = KIND_INT;
1566 }
1567
1568 if ( c_notaltreg ) {
1569 if ( saveaf ) {
1570 errorfmt("Cannot generate code for target that returns a value and carry flag\n",1);
1571 }
1572 // We're on 8080 and returning a value
1573 if ( save == KIND_LONG ) {
1574 ol("ld\tc,l");
1575 ol("ld\tb,h");
1576 } else if ( ( save != KIND_NONE && save != KIND_DOUBLE)) {
1577 swap();
1578 }
1579 vconst(k);
1580 ol("add\thl,sp");
1581 ol("ld\tsp,hl");
1582 if ( save == KIND_LONG ) {
1583 ol("ld\tl,c");
1584 ol("ld\th,b");
1585 } else if ( ( save != KIND_NONE && save != KIND_DOUBLE)) {
1586 swap();
1587 }
1588 return newsp;
1589 }
1590
1591 // We're on a z80 or other platform with alt registers
1592 if ( saveaf ) ol("ex\taf,af");
1593 if ( ( save != KIND_NONE && save != KIND_DOUBLE && save != KIND_LONGLONG)) ol("exx");
1594 vconst(k);
1595 ol("add\thl,sp");
1596 ol("ld\tsp,hl");
1597 if ( ( save != KIND_NONE && save != KIND_DOUBLE && save != KIND_LONGLONG)) ol("exx");
1598 if ( saveaf ) ol("ex\taf,af");
1599
1600 return newsp;
1601 }
1602
1603 /* Multiply the primary register by the length of some variable */
scale(Kind type,Type * tag)1604 void scale(Kind type, Type *tag)
1605 {
1606 switch (type) {
1607 case KIND_INT:
1608 case KIND_PTR:
1609 case KIND_FLOAT16:
1610 ol("add\thl,hl");
1611 break;
1612 case KIND_CPTR:
1613 threereg();
1614 break;
1615 case KIND_LONG:
1616 ol("add\thl,hl");
1617 ol("add\thl,hl");
1618 break;
1619 case KIND_LONGLONG:
1620 ol("add\thl,hl");
1621 ol("add\thl,hl");
1622 ol("add\thl,hl");
1623 break;
1624 case KIND_DOUBLE:
1625 if ( c_fp_size == 4 ) {
1626 ol("add\thl,hl");
1627 ol("add\thl,hl");
1628 } else {
1629 sixreg();
1630 }
1631 break;
1632 case KIND_STRUCT:
1633 /* try to avoid multiplying if possible */
1634 quikmult(KIND_INT, tag->size, YES);
1635 break;
1636 default:
1637 break;
1638 }
1639 }
1640
1641
quikmult(int type,int32_t size,char preserve)1642 static void quikmult(int type, int32_t size, char preserve)
1643 {
1644 if ( type == KIND_LONG ) {
1645 LVALUE lval = {0};
1646
1647 lval.val_type = type;
1648 lval.ltype = type_long;
1649
1650 /* Normal long multiplication is:
1651 push, push, ld hl, ld de, call l_long_mult = 11 bytes
1652 */
1653 switch ( size ) {
1654 case 0:
1655 vlongconst(0);
1656 break;
1657 case 1:
1658 break;
1659 case 65536:
1660 ol("ex\tde,hl");
1661 vconst(0);
1662 break;
1663 case 256: /* 5 bytes */
1664 ol("ld\td,e");
1665 ol("ld\te,h");
1666 ol("ld\th,l");
1667 ol("ld\tl,0");
1668 break;
1669 case 8: /* 15 bytes */
1670 ol("add\thl,hl");
1671 if ( IS_8085() ) {
1672 ol("rl\tde");
1673 } else if ( IS_8080() ) {
1674 ol("ld\ta,e");
1675 ol("rla");
1676 ol("ld\te,a");
1677 ol("ld\ta,d");
1678 ol("rla");
1679 ol("ld\td,a");
1680 } else {
1681 ol("rl\te");
1682 ol("rl\td");
1683 }
1684 /* Fall through */
1685 case 4: /* 10 bytes */
1686 ol("add\thl,hl");
1687 if ( IS_8085() ) {
1688 ol("rl\tde");
1689 } else if ( IS_8080() ) {
1690 ol("ld\ta,e");
1691 ol("rla");
1692 ol("ld\te,a");
1693 ol("ld\ta,d");
1694 ol("rla");
1695 ol("ld\td,a");
1696 } else {
1697 ol("rl\te");
1698 ol("rl\td");
1699 }
1700 /* Fall through */
1701 case 2: /* 5 bytes */
1702 ol("add\thl,hl");
1703 if ( IS_8085() ) {
1704 ol("rl\tde");
1705 } else if ( IS_8080() ) {
1706 ol("ld\ta,e");
1707 ol("rla");
1708 ol("ld\te,a");
1709 ol("ld\ta,d");
1710 ol("rla");
1711 ol("ld\td,a");
1712 } else {
1713 ol("rl\te");
1714 ol("rl\td");
1715 }
1716 break;
1717 case 8192:
1718 asl_const(&lval, 13);
1719 break;
1720 case 3: /* 13 bytes */
1721 if ( !IS_808x() ) {
1722 ol("push\tde");
1723 ol("push\thl");
1724 ol("add\thl,hl");
1725 ol("rl\te");
1726 ol("rl\td");
1727 ol("pop\tbc");
1728 ol("add\thl,bc");
1729 ol("pop\tbc");
1730 if ( IS_GBZ80() ) {
1731 ol("ld\ta,e");
1732 ol("adc\tc");
1733 ol("ld\te,a");
1734 ol("ld\ta,d");
1735 ol("adc\tb");
1736 ol("ld\td,a");
1737 } else {
1738 ol("ex\tde,hl");
1739 ol("adc\thl,bc");
1740 ol("ex\tde,hl");
1741 }
1742 break;
1743 }
1744 // Fall through all the way to default for 8080
1745 case 6: /* 19 bytes */
1746 if ( !IS_808x() ) {
1747 ol("push\tde");
1748 ol("push\thl");
1749 ol("add\thl,hl");
1750 ol("rl\te");
1751 ol("rl\td");
1752 ol("pop\tbc");
1753 ol("add\thl,bc");
1754 ol("pop\tbc");
1755 if ( IS_GBZ80() ) {
1756 ol("ld\ta,e");
1757 ol("adc\tc");
1758 ol("ld\te,a");
1759 ol("ld\ta,d");
1760 ol("adc\tb");
1761 ol("ld\td,a");
1762 } else {
1763 ol("ex\tde,hl");
1764 ol("adc\thl,bc");
1765 ol("ex\tde,hl");
1766 }
1767 ol("add\thl,hl");
1768 ol("rl\te");
1769 ol("rl\td");
1770 break;
1771 }
1772 // Fall through all the way to default for 8080
1773 case 5: /* 19 bytes */
1774 if ( !IS_808x() ) {
1775 ol("push\tde");
1776 ol("push\thl");
1777 ol("add\thl,hl");;
1778 ol("rl\te");
1779 ol("rl\td");
1780 ol("add\thl,hl");;
1781 ol("rl\te");
1782 ol("rl\td");
1783 ol("pop\tbc");
1784 ol("add\thl,bc");
1785 ol("pop\tbc");
1786 if ( IS_GBZ80() ) {
1787 ol("ld\ta,e");
1788 ol("adc\tc");
1789 ol("ld\te,a");
1790 ol("ld\ta,d");
1791 ol("adc\tb");
1792 ol("ld\td,a");
1793 } else {
1794 ol("ex\tde,hl");
1795 ol("adc\thl,bc");
1796 ol("ex\tde,hl");
1797 }
1798 break;
1799 }
1800 // Fall through all the way to default for 8080
1801 default:
1802 lpush();
1803 vlongconst(size);
1804 callrts("l_long_mult");
1805 Zsp += 4;
1806 }
1807 return;
1808 }
1809
1810
1811 switch (size) {
1812 case 0:
1813 vconst(0);
1814 break;
1815 case 2048:
1816 ol("ld\th,l"); /* 6 bytes, 44T */
1817 ol("ld\tl,0");
1818 ol("add\thl,hl");
1819 ol("add\thl,hl");
1820 ol("add\thl,hl");
1821 break;
1822 case 1024:
1823 ol("ld\th,l"); /* 5 bytes, 33T */
1824 ol("ld\tl,0");
1825 ol("add\thl,hl");
1826 ol("add\thl,hl");
1827 break;
1828 case 512:
1829 ol("ld\th,l"); /* 4 bytes, 22T */
1830 ol("ld\tl,0");
1831 ol("add\thl,hl");
1832 break;
1833 case 256:
1834 ol("ld\th,l"); /* 3 bytes, 11T */
1835 ol("ld\tl,0");
1836 break;
1837 case 1:
1838 break;
1839 case 64:
1840 ol("add\thl,hl"); /* 6 bytes, 66T, (RCM) 6 bytes, 12T */
1841 case 32:
1842 ol("add\thl,hl");
1843 case 16:
1844 ol("add\thl,hl");
1845 case 8:
1846 ol("add\thl,hl");
1847 case 4:
1848 ol("add\thl,hl");
1849 case 2:
1850 ol("add\thl,hl");
1851 break;
1852 case 12:
1853 ol("add\thl,hl");
1854 case 6:
1855 sixreg();
1856 break;
1857 case 9:
1858 threereg();
1859 case 3:
1860 threereg();
1861 break;
1862 case 15:
1863 threereg();
1864 case 5:
1865 fivereg();
1866 break;
1867 case 10:
1868 fivereg();
1869 ol("add\thl,hl");
1870 break;
1871 case 20:
1872 fivereg();
1873 ol("add\thl,hl");
1874 ol("add\thl,hl");
1875 break;
1876 case 40:
1877 fivereg();
1878 ol("add\thl,hl");
1879 ol("add\thl,hl");
1880 ol("add\thl,hl");
1881 break;
1882 case 14:
1883 ol("add\thl,hl");
1884 case 7:
1885 sixreg();
1886 ol("add\thl,bc"); /* BC contains original value */
1887 break;
1888 case 65535:
1889 case -1:
1890 callrts("l_neg");
1891 break;
1892 default:
1893 if (preserve)
1894 ol("push\tde");
1895 const2(size);
1896 callrts("l_mult"); /* WATCH OUT!! */
1897 if (preserve)
1898 ol("pop\tde");
1899 break;
1900 }
1901 }
1902
1903
1904
1905
1906
1907 /* Multiply the primary register by three */
threereg(void)1908 static void threereg(void)
1909 {
1910 ol("ld\tb,h");
1911 ol("ld\tc,l");
1912 ol("add\thl,bc");
1913 ol("add\thl,bc");
1914 }
1915
1916 /* Multiply the primary register by five */
fivereg(void)1917 static void fivereg(void)
1918 {
1919 ol("ld\tb,h");
1920 ol("ld\tc,l");
1921 ol("add\thl,hl");;
1922 ol("add\thl,hl");;
1923 ol("add\thl,bc");
1924 }
1925
1926 /* Multiply the primary register by six */
sixreg(void)1927 static void sixreg(void)
1928 {
1929 threereg();
1930 ol("add\thl,hl");;
1931 }
1932
1933 /*
1934 * New routines start here! What we do is have a single routine for
1935 * each operation type, the routine takes an lval, and it all works
1936 * out well..honest!
1937 */
1938
1939 /* Add the primary and secondary registers (result in primary) */
zadd(LVALUE * lval)1940 void zadd(LVALUE* lval)
1941 {
1942 switch (lval->val_type) {
1943 case KIND_LONGLONG:
1944 callrts("l_i64_add");
1945 Zsp += 8;
1946 break;
1947 case KIND_LONG:
1948 case KIND_CPTR:
1949 if ( c_speed_optimisation & OPT_ADD32 && !IS_808x() && !IS_GBZ80() ) {
1950 ol("pop\tbc"); /* 7 bytes, 54T */
1951 ol("add\thl,bc");
1952 ol("ex\tde,hl");
1953 ol("pop\tbc");
1954 ol("adc\thl,bc");
1955 ol("ex\tde,hl");
1956 } else {
1957 callrts("l_long_add"); /* 3 bytes, 76 + 17 = 93T */
1958 }
1959 Zsp += 4;
1960 break;
1961 case KIND_FLOAT16:
1962 dcallrts("fadd",lval->val_type);
1963 Zsp += 2;
1964 break;
1965 case KIND_DOUBLE:
1966 dcallrts("fadd",lval->val_type);
1967 Zsp += c_fp_size;
1968 break;
1969 default:
1970 ol("add\thl,de"); // 11T
1971 }
1972 }
1973
1974
add_to_high_word(int64_t value)1975 static int add_to_high_word(int64_t value)
1976 {
1977 int16_t delta = value >> 16;
1978
1979 switch ( delta ) {
1980 case -4: // 4, 24
1981 ol("dec\tde");
1982 case -3:
1983 ol("dec\tde");
1984 case -2:
1985 ol("dec\tde");
1986 case -1:
1987 ol("dec\tde");
1988 break;
1989 case 4:
1990 ol("inc\tde");
1991 case 3:
1992 ol("inc\tde");
1993 case 2:
1994 ol("inc\tde");
1995 case 1:
1996 ol("inc\tde");
1997 break;
1998 default:
1999 return 0;
2000 }
2001 return 1; // Handled it
2002 }
2003
zadd_const(LVALUE * lval,int64_t value64)2004 void zadd_const(LVALUE *lval, int64_t value64)
2005 {
2006 int32_t value = (int32_t)value64;
2007 if ( lval->val_type == KIND_LONGLONG ) {
2008 // TODO: If 2 <= value <= 255 then there's a libsrc call to add a
2009 if ( value == 1 ) {
2010 inc(lval);
2011 } else if ( value == -1 ) {
2012 inc(lval);
2013 } else if ( value != 0 ) {
2014 llpush();
2015 vllongconst(value64);
2016 zadd(lval);
2017 }
2018 return;
2019 }
2020
2021
2022 switch (value) {
2023 case -3:
2024 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR )
2025 break;
2026 dec(lval);
2027 case -2:
2028 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR )
2029 break;
2030 dec(lval);
2031 case -1:
2032 if ( c_speed_optimisation & OPT_SUB32 ) {
2033 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
2034 // 6 bytes, 27T (best), 28T (worst)
2035 ol("ld\ta,h"); // 1, 4
2036 ol("or\tl"); // 1, 4
2037 ol("dec\thl"); // 1, 6
2038 if ( IS_808x() ) {
2039 ol("jp\tnz,ASMPC+4");
2040 } else {
2041 ol("jr\tnz,ASMPC+3"); // 2, 12/7
2042 }
2043 ol("dec\tde"); // 1, 6
2044 return;
2045 }
2046 }
2047 dec(lval); // (long) = 3 bytes = (17 + 4 + 4 + 6 + 5 + 6 + 10) = 53T (worst), 38T best
2048 return;
2049 case 0:
2050 return;
2051 case 3:
2052 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR )
2053 break;
2054 inc(lval);
2055 case 2:
2056 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR )
2057 break;
2058 inc(lval); // (long) = 66T best (6 bytes) vs 51T (10 bytes)
2059 case 1:
2060 if ( c_speed_optimisation & OPT_ADD32 ) {
2061 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
2062 // 6 bytes, 27T (best), 28T (worst)
2063 ol("inc\thl"); // 1, 6
2064 ol("ld\ta,h"); // 1, 4
2065 ol("or\tl"); // 1, 4
2066 if ( IS_808x() ) {
2067 ol("jp\tnz,ASMPC+4");
2068 } else {
2069 ol("jr\tnz,ASMPC+3"); // 2, 12/7
2070 }
2071 ol("inc\tde"); // 1, 6
2072 return;
2073 }
2074 }
2075 inc(lval); // (int) =1, 6T, (ling) = 3 + (17 + 4 + 5 + 4 + 5 + 6 + 10) = 51T worst case (17 + 4 + 11 = 33T = best)
2076 return;
2077 }
2078 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
2079 uint32_t highword = ((uint32_t)value) / 65536;
2080 if ( (value % 65536) == 0 ) {
2081 if ( add_to_high_word(value) == 0 ) {
2082 swap(); // 1, 4
2083 addbchl(((uint32_t)value) / 65536); // 4, 21
2084 swap(); // 4
2085 }
2086 return;
2087 }
2088
2089 // 10/11 bytes, 51/54T vs 11 bytes + l_long_add ( 11 + 11 + 10 + 10 + 17 + 76 = 135T)
2090 // If < 65536 - 7 bytes, 33T (best), 34T (worst)
2091 constbc(((uint32_t)value) % 65536); // 3, 10
2092 ol("add\thl,bc"); // 1, 11
2093 if ( value >= 0 && value < 65536 ) {
2094 if ( IS_808x() ) {
2095 ol("jp\tnc,ASMPC+4");
2096 } else {
2097 ol("jr\tnc,ASMPC+3"); // 2, 12/7
2098 }
2099 ol("inc\tde"); // 1, 6
2100 } else if ( highword <= 4 ) {
2101 if ( IS_808x() ) {
2102 ol("jp\tnc,ASMPC+4");
2103 } else {
2104 ol("jr\tnc,ASMPC+3"); // 2, 12/7
2105 }
2106 ol("inc\tde"); // 1, 6
2107 add_to_high_word(value); // it will be < 7 bytes, 33T
2108 } else if ( highword >= 65532 && highword <= 65535 ) {
2109 // Jump into the block of dec de that we produce
2110 if ( IS_808x() ) {
2111 ol("jp\tc,ASMPC+4");
2112 } else {
2113 ol("jr\tc,ASMPC+3"); // 2, 12/7
2114 }
2115 add_to_high_word(value); // it will be < 7 bytes, 33T
2116 } else {
2117 ol("ex\tde,hl"); // 1, 4
2118 // TODO: 8080/gbz80 - this adc is emulated and we could probably do better with an 8 bit operation
2119 constbc(((uint32_t)value) / 65536); // 3, 10
2120 ol("adc\thl,bc"); // 2, 15
2121 ol("ex\tde,hl"); // 1, 4
2122 }
2123
2124 } else {
2125 if ( value % 256 == 0 ) {
2126 switch ( value / 256 ) {
2127 case 3:
2128 ol("inc\th");
2129 case 2:
2130 ol("inc\th");
2131 case 1:
2132 ol("inc\th");
2133 break;
2134 case -3:
2135 ol("dec\th");
2136 case -2:
2137 ol("dec\th");
2138 case -1:
2139 ol("dec\th");
2140 break;
2141 default:
2142 loada(value / 256);
2143 ol("add\th");
2144 ol("ld\th,a");
2145 }
2146 } else {
2147 addbchl(value);
2148 }
2149 }
2150 }
2151
2152 /* Subtract the primary register from the secondary */
2153 /* (results in primary) */
zsub(LVALUE * lval)2154 void zsub(LVALUE* lval)
2155 {
2156 switch (lval->val_type) {
2157 case KIND_LONGLONG:
2158 callrts("l_i64_sub");
2159 Zsp += 8;
2160 break;
2161 case KIND_LONG:
2162 case KIND_CPTR:
2163 if ( c_speed_optimisation & OPT_SUB32 && !IS_8080() && !IS_GBZ80() ) {
2164 ol("ld\tc,l"); /* 13 bytes: 4 + 4 + 10 + 4 + 15 + 4 + 4 + 4 + 10 + 15 + 4 = 78T */
2165 ol("ld\tb,h");
2166 ol("pop\thl");
2167 ol("and\ta");
2168 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
2169 ol("ex\tde,hl");
2170 ol("ld\tc,l");
2171 ol("ld\tb,h");
2172 ol("pop\thl");
2173 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
2174 ol("ex\tde,hl");
2175 } else {
2176 callrts("l_long_sub"); /* 3 bytes: 100 + 17T = 117t */
2177 }
2178 Zsp += 4;
2179 break;
2180 case KIND_FLOAT16:
2181 dcallrts("fsub",lval->val_type);
2182 Zsp += 2;
2183 break;
2184 case KIND_DOUBLE:
2185 dcallrts("fsub",lval->val_type);
2186 Zsp += c_fp_size;
2187 break;
2188 default:
2189 if ( c_speed_optimisation & OPT_SUB16 && !IS_808x() && !IS_GBZ80()) {
2190 swap();
2191 ol("and\ta");
2192 ol("sbc\thl,de");
2193 } else {
2194 callrts("l_sub");
2195 }
2196 }
2197 }
2198
2199 /* Multiply the primary and secondary registers */
2200 /* (results in primary */
mult(LVALUE * lval)2201 void mult(LVALUE* lval)
2202 {
2203 switch (lval->val_type) {
2204 case KIND_LONGLONG:
2205 callrts("l_i64_mult");
2206 Zsp += 8;
2207 break;
2208 case KIND_LONG:
2209 case KIND_CPTR:
2210 callrts("l_long_mult");
2211 Zsp += 4;
2212 break;
2213 case KIND_FLOAT16:
2214 dcallrts("fmul",lval->val_type);
2215 Zsp += 2;
2216 break;
2217 case KIND_DOUBLE:
2218 dcallrts("fmul",lval->val_type);
2219 Zsp += c_fp_size;
2220 break;
2221 case KIND_CHAR:
2222 if ( lval->ltype->isunsigned ) {
2223 if (c_cpu == CPU_Z180 ) {
2224 ot("ld\th,e\n");
2225 ot("mlt\thl\n");
2226 break;
2227 } else if ( (c_cpu & CPU_RABBIT) ) {
2228 // For Rabbit we want to use the mul instruction
2229 } else if ( c_speed_optimisation & OPT_UCHAR_MULT ) {
2230 int label1 = getlabel();
2231 int label2 = getlabel();
2232 ol("ld\th,l");
2233 ol("ld\tl,0");
2234 ol("ld\td,l");
2235 ol("ld\tb,8");
2236 postlabel(label1);
2237 opjumpr("nc,",label2);
2238 ol("add\thl,de");
2239 postlabel(label2);
2240 outfmt("\tdjnz\ti_%d\n",label1);
2241 break;
2242 }
2243 }
2244 default:
2245 callrts("l_mult");
2246 }
2247 }
2248
mult_const(LVALUE * lval,int64_t value64)2249 void mult_const(LVALUE *lval, int64_t value64)
2250 {
2251 int32_t value = (int32_t)value64;
2252 if ( lval->val_type == KIND_LONGLONG ) {
2253 int c = 0;
2254 int64_t p = value64;
2255 // Determine if it's a power of two:
2256 while (((p & 1) == 0) && p > 1) { /* While x is even and > 1 */
2257 c++;
2258 p >>= 1;
2259 }
2260 if ( p == 1 ) {
2261 llpush();
2262 loada(c);
2263 callrts("l_i64_aslo");
2264 Zsp += 8;
2265 } else {
2266 llpush();
2267 vllongconst(value);
2268 callrts("l_i64_mult");
2269 Zsp += 8;
2270 }
2271 return;
2272 } else {
2273 quikmult(lval->val_type, value, NO);
2274 }
2275 }
2276
mult_dconst(LVALUE * lval,double value,int isrhs)2277 int mult_dconst(LVALUE *lval, double value, int isrhs)
2278 {
2279 int exp;
2280
2281 if ( value == 1.0 ) {
2282 return 1;
2283 } else if ( frexp(value, &exp) == 0.5 ) {
2284 // It's a power of two so we can nobble the exponent
2285 loada(exp - 1);
2286 dcallrts("ldexp",lval->val_type);
2287 return 1;
2288 }
2289
2290 return 0;
2291 }
2292
2293
2294 /* Divide the secondary register by the primary */
2295 /* (quotient in primary, remainder in secondary) */
zdiv(LVALUE * lval)2296 void zdiv(LVALUE* lval)
2297 {
2298 switch (lval->val_type) {
2299 case KIND_LONGLONG:
2300 if (ulvalue(lval))
2301 callrts("l_i64_div_u");
2302 else
2303 callrts("l_i64_div");
2304 Zsp += 8;
2305 break;
2306 case KIND_LONG:
2307 case KIND_CPTR:
2308 if (ulvalue(lval))
2309 callrts("l_long_div_u");
2310 else
2311 callrts("l_long_div");
2312 Zsp += 4;
2313 break;
2314 case KIND_FLOAT16:
2315 dcallrts("fdiv",lval->val_type);
2316 Zsp += 2;
2317 break;
2318 case KIND_DOUBLE:
2319 dcallrts("fdiv",lval->val_type);
2320 Zsp += c_fp_size;
2321 break;
2322 default:
2323 if (ulvalue(lval))
2324 callrts("l_div_u");
2325 else
2326 callrts("l_div");
2327 }
2328 }
2329
add_if_negative(LVALUE * lval,int32_t toadd)2330 static void add_if_negative(LVALUE *lval, int32_t toadd)
2331 {
2332 int label;
2333
2334 if ( ulvalue(lval) )
2335 return;
2336 label = getlabel();
2337 if ( lval->val_type == KIND_LONG ) {
2338 if ( IS_808x() ) {
2339 ol("ld\ta,d");
2340 ol("rla");
2341 ot("jp\tnc,");
2342 } else {
2343 ol("bit\t7,d");
2344 ot("jr\tz,");
2345 }
2346 printlabel(label);
2347 nl();
2348 } else {
2349 if ( IS_808x() ) {
2350 ol("ld\ta,h");
2351 ol("rla");
2352 ot("jp\tnc,");
2353 } else {
2354 ol("bit\t7,h");
2355 ot("jr\tz,");
2356 }
2357 printlabel(label);
2358 nl();
2359 }
2360 zadd_const(lval,toadd);
2361 postlabel(label);
2362 }
2363
zdiv_const(LVALUE * lval,int64_t value64)2364 void zdiv_const(LVALUE *lval, int64_t value64)
2365 {
2366 int32_t value = (int32_t)value64;
2367 if ( lval->val_type == KIND_LONGLONG ) {
2368 llpush();
2369 vllongconst(value64);
2370 zdiv(lval);
2371 return;
2372 } else if ( lval->val_type == KIND_LONG && ulvalue(lval) ) {
2373 if ( value == 256 ) {
2374 ol("ld\tl,h");
2375 ol("ld\th,e");
2376 ol("ld\te,d");
2377 ol("ld\td,0");
2378 return;
2379 } else if ( value == 8192 && ulvalue(lval) ) {
2380 asr_const(lval, 13);
2381 return;
2382 } else if ( value == 65536 ) {
2383 swap();
2384 const2(0);
2385 return;
2386 }
2387 } else if ( lval->val_type == KIND_INT && ulvalue(lval) ) {
2388 if ( value == 512 && !IS_808x()) {
2389 ol("ld\tl,h");
2390 ol("ld\th,0");
2391 ol("srl\tl");
2392 return;
2393 } else if ( value == 256 ) {
2394 ol("ld\tl,h");
2395 ol("ld\th,0");
2396 return;
2397 }
2398 }
2399
2400 switch ( value ) {
2401 case 1:
2402 break;
2403 case 2:
2404 add_if_negative(lval, 1);
2405 asr_const(lval,1);
2406 break;
2407 case 4:
2408 add_if_negative(lval, 3);
2409 asr_const(lval,2);
2410 break;
2411 case 8:
2412 add_if_negative(lval, 7);
2413 asr_const(lval,3);
2414 break;
2415 case 16:
2416 add_if_negative(lval, 15);
2417 asr_const(lval,4);
2418 break;
2419 case 32:
2420 add_if_negative(lval, 31);
2421 asr_const(lval,5);
2422 break;
2423 case 64:
2424 add_if_negative(lval, 63);
2425 asr_const(lval,6);
2426 break;
2427 case 128:
2428 add_if_negative(lval, 127);
2429 asr_const(lval,7);
2430 break;
2431 case 256:
2432 /* Unsigned is dealt with above */
2433 add_if_negative(lval, 255);
2434 asr_const(lval,8);
2435 break;
2436 default:
2437 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
2438 lpush();
2439 vlongconst(value);
2440 } else {
2441 const2(value & 0xffff);
2442 swap();
2443 }
2444 zdiv(lval);
2445 }
2446 }
2447
zdiv_dconst(LVALUE * lval,double value,int isrhs)2448 int zdiv_dconst(LVALUE *lval, double value, int isrhs)
2449 {
2450 if ( isrhs == 0 && value == 1.0 &&
2451 (c_maths_mode == MATHS_IEEE || lval->val_type == KIND_FLOAT16)) {
2452 dcallrts("inversef",lval->val_type);
2453 return 1;
2454 }
2455 return 0;
2456 }
2457
2458
2459 /* Compute remainder (mod) of secondary register divided
2460 * by the primary
2461 * (remainder in primary, quotient in secondary)
2462 */
zmod(LVALUE * lval)2463 void zmod(LVALUE* lval)
2464 {
2465 if (c_notaltreg && (lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR)) {
2466 if (ulvalue(lval))
2467 callrts("l_long_mod_u");
2468 else
2469 callrts("l_long_mod");
2470 Zsp += 4;
2471 } else {
2472 if ( IS_GBZ80() ) {
2473 if (ulvalue(lval))
2474 callrts("l_mod_u");
2475 else
2476 callrts("l_mod");
2477 } else if ( lval->val_type == KIND_LONGLONG) {
2478 if (ulvalue(lval))
2479 callrts("l_i64_mod_u");
2480 else
2481 callrts("l_i64_mod");
2482 } else if (lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
2483 if (ulvalue(lval))
2484 callrts("l_long_mod_u");
2485 else
2486 callrts("l_long_mod");
2487 Zsp += 4;
2488 } else {
2489 zdiv(lval);
2490 swap();
2491 }
2492 }
2493 }
2494
negate_if_negative(LVALUE * lval,int64_t value)2495 void negate_if_negative(LVALUE *lval, int64_t value)
2496 {
2497 int label;
2498 // Only need to consider int handling here
2499 // We're called for parameters on the lowest byte, so only need to consider l
2500 if ( ulvalue(lval) )
2501 return;
2502 label = getlabel();
2503 if ( lval->val_type == KIND_LONG ) {
2504 if ( IS_808x() ) {
2505 ol("ld\ta,d");
2506 ol("rla");
2507 ot("jp\tnc,");
2508 } else {
2509 ol("bit\t7,d");
2510 ot("jr\tz,");
2511 }
2512 printlabel(label);
2513 nl();
2514 } else {
2515 if ( IS_808x() ) {
2516 ol("ld\ta,h");
2517 ol("rla");
2518 ot("jp\tnc,");
2519 } else {
2520 ol("bit\t7,h");
2521 ot("jr\tz,");
2522 }
2523 printlabel(label);
2524 nl();
2525 }
2526 ol("ld\ta,l");
2527 ol("cpl");
2528 ol("inc\ta");
2529 ol("ld\tl,a");
2530 postlabel(label);
2531 }
2532
zmod_const(LVALUE * lval,int64_t value64)2533 void zmod_const(LVALUE *lval, int64_t value64)
2534 {
2535 LVALUE templval={0};
2536 int32_t value = (int32_t)value64;
2537
2538 templval.val_type = KIND_INT;
2539 if ( ulvalue(lval) )
2540 templval.ltype = type_uint;
2541 else
2542 templval.ltype = type_int;
2543
2544 if ( lval->val_type == KIND_LONG ) {
2545 if ( value <= 256 && value > 0 ) {
2546 zmod_const(&templval, value);
2547 const2(0);
2548 return;
2549 } else if ( value == 65536 && ulvalue(lval) ) {
2550 const2(0);
2551 return;
2552 } else if ( value == 65536 * 256 && ulvalue(lval) ) {
2553 ol("ld\td,0");
2554 return;
2555 } else if ( value == 8192 && ulvalue(lval) ) {
2556 zand_const(lval, 8191);
2557 return;
2558 } else {
2559 lpush();
2560 vlongconst(value);
2561 zmod(lval);
2562 return;
2563 }
2564 } else if ( lval->val_type == KIND_LONGLONG) {
2565 llpush();
2566 vllongconst(value64);
2567 zmod(lval);
2568 return;
2569 }
2570
2571 switch ( value ) {
2572 case 1:
2573 vconst(0);
2574 break;
2575 case 2:
2576 negate_if_negative(lval, 1);
2577 zand_const(&templval,1);
2578 break;
2579 case 4:
2580 negate_if_negative(lval, 3);
2581 zand_const(&templval, 3);
2582 break;
2583 case 8:
2584 negate_if_negative(lval, 7);
2585 zand_const(&templval,7);
2586 break;
2587 case 16:
2588 negate_if_negative(lval, 15);
2589 zand_const(&templval,15);
2590 break;
2591 case 32:
2592 negate_if_negative(lval, 31);
2593 zand_const(&templval, 31);
2594 break;
2595 case 64:
2596 negate_if_negative(lval, 63);
2597 zand_const(&templval,63);
2598 break;
2599 case 128:
2600 negate_if_negative(lval, 127);
2601 zand_const(&templval,127);
2602 break;
2603 case 256:
2604 if ( ulvalue(lval) ) {
2605 ol("ld\th,0");
2606 } else {
2607 negate_if_negative(lval, 255);
2608 ol("ld\th,0");
2609 }
2610 break;
2611 default:
2612 const2(value & 0xffff);
2613 swap();
2614 zmod(&templval);
2615 }
2616 }
2617
2618 /* Inclusive 'or' the primary and secondary */
2619 /* (results in primary) */
zor(LVALUE * lval)2620 void zor(LVALUE* lval )
2621 {
2622 switch (lval->val_type) {
2623 case KIND_LONGLONG:
2624 callrts("l_i64_or");
2625 Zsp += 8;
2626 break;
2627 case KIND_LONG:
2628 case KIND_CPTR:
2629 callrts("l_long_or");
2630 Zsp += 4;
2631 break;
2632 default:
2633 callrts("l_or");
2634 }
2635 }
2636
2637
zor_handle_pow2(int64_t value)2638 int zor_handle_pow2(int64_t value)
2639 {
2640 int c = 0;
2641 switch ( value ) {
2642 case 0:
2643 return 1;
2644 case 0x80:
2645 c++;
2646 case 0x40:
2647 c++;
2648 case 0x20:
2649 c++;
2650 case 0x10:
2651 c++;
2652 case 0x08:
2653 c++;
2654 case 0x04:
2655 c++;
2656 case 0x02:
2657 c++;
2658 case 0x01:
2659 c++;
2660 if ( IS_808x() ) return 0;
2661 outfmt("\tset\t%d,l\n",c-1);
2662 break;
2663 case 0x8000:
2664 c++;
2665 case 0x4000:
2666 c++;
2667 case 0x2000:
2668 c++;
2669 case 0x1000:
2670 c++;
2671 case 0x800:
2672 c++;
2673 case 0x400:
2674 c++;
2675 case 0x200:
2676 c++;
2677 case 0x100:
2678 c++;
2679 if ( IS_808x() ) return 0;
2680 outfmt("\tset\t%d,h\n",c-1);
2681 break;
2682 case 0x800000:
2683 c++;
2684 case 0x400000:
2685 c++;
2686 case 0x200000:
2687 c++;
2688 case 0x100000:
2689 c++;
2690 case 0x80000:
2691 c++;
2692 case 0x40000:
2693 c++;
2694 case 0x20000:
2695 c++;
2696 case 0x10000:
2697 c++;
2698 if ( IS_808x() ) return 0;
2699 outfmt("\tset\t%d,e\n",c-1);
2700 break;
2701 case 0x80000000:
2702 c++;
2703 case 0x40000000:
2704 c++;
2705 case 0x20000000:
2706 c++;
2707 case 0x10000000:
2708 c++;
2709 case 0x8000000:
2710 c++;
2711 case 0x4000000:
2712 c++;
2713 case 0x2000000:
2714 c++;
2715 case 0x1000000:
2716 c++;
2717 if ( IS_808x() ) return 0;
2718 outfmt("\tset\t%d,d\n",c-1);
2719 break;
2720 }
2721 return c;
2722 }
2723
2724
zor_const(LVALUE * lval,int64_t value64)2725 void zor_const(LVALUE *lval, int64_t value64)
2726 {
2727 int32_t value = (int32_t)value64;
2728 if ( lval->val_type == KIND_LONGLONG ) {
2729 llpush();
2730 vllongconst(value64);
2731 zor(lval);
2732 } else if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
2733 if ( zor_handle_pow2(value) ) {
2734 return;
2735 } else if ( (value & 0xFFFFFF00) == 0 ) {
2736 ol("ld\ta,l");
2737 ot("or\t"); outdec((value & 0xff)); nl();
2738 ol("ld\tl,a");
2739 } else if ( ( value & 0xFFFF00FF) == 0 ) {
2740 ol("ld\ta,h");
2741 ot("or\t"); outdec((value & 0xff00) >> 8); nl();
2742 ol("ld\th,a");
2743 } else if ( ( value & 0xFF00FFFF) == 0 ) {
2744 ol("ld\ta,e");
2745 ot("or\t"); outdec((value & 0xff0000) >> 16); nl();
2746 ol("ld\te,a");
2747 } else if ( ( value & 0x00FFFFFF) == 0 ) {
2748 ol("ld\ta,d");
2749 ot("or\t"); outdec((value & 0xff000000) >> 24); nl();
2750 ol("ld\td,a");
2751 } else if ( value != 0 ) {
2752 lpush();
2753 vlongconst(value);
2754 zor(lval);
2755 }
2756 } else {
2757 if ( zor_handle_pow2(value % 65536) ) {
2758 return;
2759 } else if ( ((value % 65536) & 0xff00) == 0 ) {
2760 ol("ld\ta,l");
2761 ot("or\t"); outdec(value & 0xff); nl();
2762 ol("ld\tl,a");
2763 } else if ( ((value % 65536) & 0x00ff) == 0 ) {
2764 ol("ld\ta,h");
2765 ot("or\t"); outdec((value & 0xff00) >> 8); nl();
2766 ol("ld\th,a");
2767 } else if ( value != 0 ) {
2768 const2(value & 0xffff);
2769 zor(lval);
2770 }
2771 }
2772 }
2773
2774 /* Exclusive 'or' the primary and secondary */
2775 /* (results in primary) */
zxor(LVALUE * lval)2776 void zxor(LVALUE *lval)
2777 {
2778 switch (lval->val_type) {
2779 case KIND_LONGLONG:
2780 callrts("l_i64_xor");
2781 Zsp += 8;
2782 break;
2783 case KIND_LONG:
2784 case KIND_CPTR:
2785 callrts("l_long_xor");
2786 Zsp += 4;
2787 break;
2788 default:
2789 callrts("l_xor");
2790 }
2791 }
2792
zxor_const(LVALUE * lval,int64_t value64)2793 void zxor_const(LVALUE *lval, int64_t value64)
2794 {
2795 int32_t value = (int32_t)value64;
2796 if ( lval->val_type == KIND_LONGLONG ) {
2797 llpush();
2798 vllongconst(value64);
2799 zxor(lval);
2800 } else if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
2801 if ( (value & 0xFFFFFF00) == 0 ) {
2802 ol("ld\ta,l");
2803 ot("xor\t"); outdec(value % 256); nl();
2804 ol("ld\tl,a");
2805 } else if ( ( value & 0xFFFF00FF) == 0 ) {
2806 ol("ld\ta,h");
2807 ot("xor\t"); outdec((value & 0xff00) >> 8); nl();
2808 ol("ld\th,a");
2809 } else if ( ( value & 0xFF00FFFF) == 0 ) {
2810 ol("ld\ta,e");
2811 ot("xor\t"); outdec((value & 0xff0000) >> 16); nl();
2812 ol("ld\te,a");
2813 } else if ( ( value & 0x00FFFFFF) == 0 ) {
2814 ol("ld\ta,d");
2815 ot("xor\t"); outdec((value & 0xff000000) >> 24); nl();
2816 ol("ld\td,a");
2817 } else if ( ( value & 0xffffffff) == 0xffffffff ) {
2818 com(lval);
2819 } else if ( value != 0 ) {
2820 lpush();
2821 vlongconst(value);
2822 zxor(lval);
2823 }
2824 } else {
2825 if ( ((value % 65536) & 0xff00) == 0 ) {
2826 ol("ld\ta,l");
2827 ot("xor\t"); outdec(value & 0xff); nl();
2828 ol("ld\tl,a");
2829 } else if ( ((value % 65536) & 0x00ff) == 0 ) {
2830 ol("ld\ta,h");
2831 ot("xor\t"); outdec((value & 0xff00) >> 8); nl();
2832 ol("ld\th,a");
2833 } else if ( ( value & 0xffff) == 0xffff ) {
2834 com(lval);
2835 } else if ( value != 0 ) {
2836 const2(value & 0xffff);
2837 zxor(lval);
2838 }
2839 }
2840 }
2841
2842
2843 /* 'And' the primary and secondary */
2844 /* (results in primary) */
zand(LVALUE * lval)2845 void zand(LVALUE* lval)
2846 {
2847 switch (lval->val_type) {
2848 case KIND_LONGLONG:
2849 callrts("l_i64_and");
2850 Zsp += 8;
2851 break;
2852 case KIND_LONG:
2853 case KIND_CPTR:
2854 callrts("l_long_and");
2855 Zsp += 4;
2856 break;
2857 default:
2858 callrts("l_and");
2859 }
2860 }
2861
zand_const(LVALUE * lval,int64_t value64)2862 void zand_const(LVALUE *lval, int64_t value64)
2863 {
2864 int32_t value = (int32_t)value64;
2865 if ( lval->val_type == KIND_LONGLONG ) {
2866 llpush();
2867 vllongconst(value64);
2868 zand(lval);
2869 } else if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
2870 if ( value == 0 ) {
2871 vlongconst(0);
2872 } else if ( value == 0xff ) { // 5
2873 ol("ld\th,0");
2874 const2(0);
2875 } else if ( value >= 0 && value < 256 ) { // 9 bytes
2876 ol("ld\ta,l");
2877 ot("and\t"); outdec(value % 256); nl();
2878 ol("ld\tl,a");
2879 ol("ld\th,0");
2880 const2(0);
2881 } else if ( value == 0xffff ) { // 3 bytes
2882 const2(0);
2883 } else if ( value == 0xffffff ) { // 2 bytes
2884 ol("ld\td,0");
2885 } else if ( value == 0xffffffff ) {
2886 // Do nothing
2887 } else if ( (value & 0xffffff00) == 0xffffff00 ) {
2888 // Only the bottom 8 bits
2889 ol("ld\ta,l");
2890 outfmt("\tand\t+(%d %% 256)\n",(value & 0xff));
2891 ol("ld\tl,a");
2892 } else if ( (value & 0xffff00ff) == 0xffff00ff ) {
2893 // Only the bits 15-8
2894 ol("ld\ta,h");
2895 outfmt("\tand\t+(%d %% 256)\n",(value & 0xff00)>>8);
2896 ol("ld\th,a");
2897 } else if ( (value & 0xff00ffff ) == 0xff00ffff) {
2898 // Only the bits 23-16
2899 ol("ld\ta,e");
2900 outfmt("\tand\t+(%d %% 256)\n",(value & 0xff0000)>>16);
2901 ol("ld\te,a");
2902 } else if ( (value & 0x00ffffff) == 0x00ffffff ) {
2903 // Only the bits 32-23
2904 ol("ld\ta,d");
2905 outfmt("\tand\t+(%d %% 256)\n",(value & 0xff000000) >> 24);
2906 ol("ld\td,a");
2907 } else if ( (value & 0xffff0000) == 0x00000000 ) {
2908 LVALUE tval = {0};
2909
2910 tval.val_type = KIND_INT;
2911 tval.ltype = type_int;
2912 zand_const(&tval, value % 65536);
2913 const2(0);
2914 } else { // 13 bytes
2915 lpush(); // 4
2916 vlongconst(value); // 6
2917 zand(lval); // 3
2918 }
2919 } else {
2920 uint16_t val = value;
2921 if ( val == 0 ) {
2922 vconst(0);
2923 } else if ( (value % 65536) == 0xff ) {
2924 ol("ld\th,0");
2925 } else if ( value >= 0 && value < 256 ) {
2926 // 6 bytes, library call is 6 bytes, this is faster
2927 ol("ld\ta,l");
2928 outfmt("\tand\t+(%d %% 256)\n",value % 256);
2929 ol("ld\tl,a");
2930 ol("ld\th,0");
2931 } else if ( value % 256 == 0 ) {
2932 ol("ld\ta,h");
2933 outfmt("\tand\t+(%d %% 256)\n",(value & 0xff00) >> 8);
2934 ol("ld\th,a");
2935 ol("ld\tl,0");
2936 } else if ( value == (uint16_t)0xffff ) {
2937 // Do nothing
2938 } else if ( val == 0xfffe ) {
2939 if ( IS_808x() ) {
2940 ol("ld\ta,l");
2941 ol("and\t254");
2942 ol("ld\tl,a");
2943 } else {
2944 ol("res\t0,l");
2945 }
2946 } else {
2947 const2(value & 0xffff);
2948 zand(lval);
2949 }
2950 }
2951 }
2952
2953 /* Arithmetic shift right the secondary register number of */
2954 /* times in primary (results in primary) */
asr(LVALUE * lval)2955 void asr(LVALUE* lval)
2956 {
2957 switch (lval->val_type) {
2958 case KIND_LONGLONG:
2959 if (ulvalue(lval))
2960 callrts("l_i64_asr_u");
2961 else
2962 callrts("l_i64_asr");
2963 Zsp += 8;
2964 break;
2965 case KIND_LONG:
2966 case KIND_CPTR:
2967 if (ulvalue(lval))
2968 callrts("l_long_asr_u");
2969 else
2970 callrts("l_long_asr");
2971 Zsp += 4;
2972 break;
2973 default:
2974 if (ulvalue(lval))
2975 callrts("l_asr_u");
2976 else
2977 callrts("l_asr");
2978 }
2979 }
2980
asr_const(LVALUE * lval,int64_t value64)2981 void asr_const(LVALUE *lval, int64_t value64)
2982 {
2983 int32_t value = (int32_t)value64;
2984 if ( lval->val_type == KIND_CHAR && ulvalue(lval) ) {
2985 int i;
2986 if ( value == 0 ) {
2987 return;
2988 } else if ( value >= 5 ) {
2989 int rotate_count = 8 - value;
2990 ol("ld\ta,l");
2991 if ( value == 5 && (IS_GBZ80() || IS_Z80N()) ) {
2992 rotate_count -= 4;
2993 if ( IS_GBZ80() ) ol("swap\ta"); else ol("swapnib");
2994 }
2995 for ( i = rotate_count; i < 0; i++ ) {
2996 ol("rrca");
2997 }
2998 for ( i = 0; i < rotate_count; i++ ) {
2999 ol("rlca");
3000 }
3001 outfmt("\tand\t%d\n", ( ((1 << (8-value)) - 1)));
3002 ol("ld\tl,a");
3003 return;
3004 } else if (value < 8 ) {
3005 int rotate_count = value;
3006 ol("ld\ta,l");
3007 if ( value >= 4 && (IS_GBZ80() || IS_Z80N()) ) {
3008 rotate_count -= 4;
3009 if ( IS_GBZ80() ) ol("swap\ta"); else ol("swapnib");
3010 }
3011 for ( i = 0; i <rotate_count; i++ ) {
3012 ol("rrca");
3013 }
3014 outfmt("\tand\t%d\n", ( ((1 << (8-value)) - 1)));
3015 ol("ld\tl,a");
3016 return;
3017 }
3018 }
3019
3020 if (lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
3021 if ( value == 1 && !IS_808x() ) {
3022 if ( ulvalue(lval) ) { /* 8 bytes, 8 + 8 + 8 + 8 + 8 = 40T */
3023 ol("srl\td");
3024 } else {
3025 ol("sra\td");
3026 }
3027 ol("rr\te");
3028 ol("rr\th");
3029 ol("rr\tl");
3030 } else if ( value == 8 ) {
3031 if ( ulvalue(lval) ) { /* 5 bytes, 4 + 4 + 4 +7 = 19T */
3032 ol("ld\tl,h");
3033 ol("ld\th,e");
3034 ol("ld\te,d");
3035 ol("ld\td,0");
3036 } else { /* 9 bytes, 28T */
3037 ol("ld\tl,h");
3038 ol("ld\th,e");
3039 ol("ld\te,d");
3040 ol("ld\ta,d");
3041 ol("rlca");
3042 ol("sbc\ta");
3043 ol("ld\td,a");
3044 }
3045 } else if ( value == 9 && ulvalue(lval) ) {
3046 ol("ld\tl,h"); /* 5 bytes, 4+ 4 +4 +7 */
3047 ol("ld\th,e");
3048 ol("ld\te,d");
3049 ol("ld\td,0");
3050 if ( IS_808x() ) {
3051 ol("and\ta"); // 16 bytes + 40T = 59T
3052 ol("ld\ta,e");
3053 ol("rra");
3054 ol("ld\te,a");
3055 ol("ld\ta,h");
3056 ol("rra");
3057 ol("ld\th,a");
3058 ol("ld\ta,l");
3059 ol("rra");
3060 ol("ld\tl,a");
3061 } else { // z80 + 8 +8 + 8 = 43T, 11 bytes
3062 ol("srl\te");
3063 ol("rr\th");
3064 ol("rr\tl");
3065 }
3066 } else if ( value == 10 && ulvalue(lval) && (c_speed_optimisation & OPT_RSHIFT32) && !IS_808x() ) {
3067 ol("ld\tl,h"); /* 17 bytes, 19 + 48 = 67T */
3068 ol("ld\th,e");
3069 ol("ld\te,d");
3070 ol("ld\td,0");
3071 ol("srl\te");
3072 ol("rr\th");
3073 ol("rr\tl");
3074 ol("srl\te");
3075 ol("rr\th");
3076 ol("rr\tl");
3077 } else if ( (value == 11 || value == 12 || value == 13 || value == 14 ) && ulvalue(lval) ) {
3078 ol("ld\tl,h"); /* 12 bytes - shift by 8 initially */
3079 ol("ld\th,e");
3080 ol("ld\te,d");
3081 ol("ld\td,0");
3082 ot("ld\tc,"); outdec(value -8); nl();
3083 callrts("l_long_asr_uo");
3084 } else if ( value == 15 && ulvalue(lval) && !IS_808x() ) {
3085 if ( IS_GBZ80() ) {
3086 ol("rl\th");
3087 ol("ld\ta,e");
3088 ol("adc\te");
3089 ol("ld\tl,a");
3090 ol("ld\ta,d");
3091 ol("adc\td");
3092 ol("ld\th,a");
3093 } else {
3094 ol("ex\tde,hl"); /* 10 bytes, 45T */
3095 ol("rl\td"); // Lowest bit
3096 ol("adc\thl,hl");
3097 }
3098 ol("ld\tde,0");
3099 ol("rl\te");
3100 } else if ( value == 16 ) {
3101 if ( ulvalue(lval)) {
3102 ol("ex\tde,hl"); /* 4 bytes 14T */
3103 ol("ld\tde,0");
3104 } else {
3105 ol("ex\tde,hl"); /* 6 bytes 20T */
3106 ol("ld\ta,h");
3107 ol("rlca");
3108 ol("sbc\ta");
3109 ol("ld\td,a");
3110 ol("ld\te,a");
3111 }
3112 } else if ( value == 17 && ulvalue(lval)) {
3113 if ( IS_808x()) {
3114 ol("and\ta"); // 10 bytes, 38T
3115 ol("ld\ta,d");
3116 ol("rra");
3117 ol("ld\th,a");
3118 ol("ld\ta,e");
3119 ol("rra");
3120 ol("ld\tl,a");
3121 } else {
3122 ol("srl\td"); /* 8 bytes 30T */
3123 ol("rr\te");
3124 if ( IS_GBZ80() ) {
3125 ol("ld\tl,e");
3126 ol("ld\th,d");
3127 } else {
3128 ol("ex\tde,hl");
3129 }
3130 }
3131 ol("ld\tde,0");
3132 } else if ( value == 18 && ulvalue(lval) && !IS_808x()) {
3133 if ( IS_GBZ80() ) {
3134 ol("ld\tl,e");
3135 ol("ld\th,d");
3136 ol("ld\tde,0");
3137 } else {
3138 ol("ld\thl,0"); /* 12 bytes, 46T */
3139 ol("ex\tde,hl");
3140 }
3141 ol("srl\th");
3142 ol("rr\tl");
3143 ol("srl\th");
3144 ol("rr\tl");
3145 } else if ( value == 20 && ulvalue(lval) && (c_speed_optimisation & OPT_RSHIFT32) && !IS_808x() ) {
3146 if ( IS_GBZ80() ) {
3147 ol("ld\tl,e");
3148 ol("ld\th,d");
3149 } else {
3150 ol("ex\tde,hl"); /* 20 bytes, 78T */
3151 }
3152 ol("ld\tde,0");
3153 ol("srl\th");
3154 ol("rr\tl");
3155 ol("srl\th");
3156 ol("rr\tl");
3157 ol("srl\th");
3158 ol("rr\tl");
3159 ol("srl\th");
3160 ol("rr\tl");
3161 } else if ( value == 23 && ulvalue(lval) && !IS_808x()) {
3162 ol("ld\tl,d"); /* 12 bytes, 37T */
3163 ol("rl\te");
3164 ol("rl\tl");
3165 ol("ld\th,0");
3166 ol("rl\th");
3167 ol("ld\tde,0");
3168 } else if ( value == 24 ) {
3169 if ( ulvalue(lval) ) {
3170 ol("ld\tl,d"); /* 6 bytes , 21T */
3171 ol("ld\th,0");
3172 ol("ld\tde,0");
3173 } else {
3174 ol("ld\tl,d"); /* 7 bytes , 28T */
3175 ol("ld\ta,d");
3176 ol("rlca");
3177 ol("sbc\ta");
3178 ol("ld\td,a");
3179 ol("ld\te,a");
3180 ol("ld\th,a");
3181 }
3182 } else if ( value == 25 && ulvalue(lval) && !IS_8080() ) {
3183 ol("ld\tl,d"); /* 8 bytes, 29T */
3184 ol("ld\th,0");
3185 if ( IS_8085() ) ol("sra\thl"); else ol("srl\tl");
3186 ol("ld\tde,0");
3187 } else if ( value == 27 && ulvalue(lval) && !IS_8080()) {
3188 ol("ld\tl,d"); /* 12 bytes, 47T */
3189 ol("ld\th,0");
3190 if ( IS_8085() ) ol("sra\thl"); else ol("srl\tl");
3191 if ( IS_8085() ) ol("sra\thl"); else ol("srl\tl");
3192 if ( IS_8085() ) ol("sra\thl"); else ol("srl\tl");
3193 ol("ld\tde,0");
3194 } else if ( value == 30 && ulvalue(lval) && (c_speed_optimisation & OPT_RSHIFT32) && !IS_808x() ) {
3195 ol("ld\tl,0"); /* 15 bytes, 51T */
3196 ol("rl\td");
3197 ol("rl\tl");
3198 ol("rl\td");
3199 ol("rl\tl");
3200 ol("ld\th,0");
3201 ol("ld\tde,0");
3202 } else if ( value == 31 && ulvalue(lval) && !IS_808x() ) {
3203 ol("ld\tl,0"); /* 12 bytes, 40T */
3204 ol("rl\td");
3205 ol("rl\tl");
3206 ol("ld\th,0");
3207 ol("ld\tde,0");
3208 } else if ( value != 0 ) {
3209 value &= 31;
3210 if ( value >= 16 && ulvalue(lval)) { /* 7 bytes */
3211 ot("ld\thl,");outdec( value - 16); nl(); /* We don't want it marked as const otherwise it gets optimised away */
3212 callrts("l_asr_u");
3213 ol("inc\te");
3214 } else {
3215 lpush(); /* 11 bytes, optimised to 5 */
3216 vlongconst(value);
3217 asr(lval);
3218 }
3219 }
3220 } else if ( lval->val_type == KIND_LONGLONG ) {
3221 if ( value >= 64 ) warningfmt("overflow","Left shifting by more than the size of the object");
3222 llpush();
3223 loada(value & 63);
3224 if (ulvalue(lval)) {
3225 callrts("l_i64_asr_uo");
3226 } else {
3227 callrts("l_i64_asro");
3228 }
3229 Zsp += 8;
3230 } else {
3231 if ( value == 1 && IS_8085() && !ulvalue(lval) ) {
3232 ol("sra\thl");
3233 } else if ( value == 1 && IS_808x() && ulvalue(lval) ) {
3234 ol("xor\ta");
3235 ol("ld\ta,h");
3236 ol("rra");
3237 ol("ld\th,a");
3238 ol("ld\ta,l");
3239 ol("rra");
3240 ol("ld\tl,a");
3241 } else if ( value == 1 && !IS_808x() ) { /* 4 bytes, 16T */
3242 if ( ulvalue(lval) ) {
3243 ol("srl\th");
3244 } else {
3245 ol("sra\th");
3246 }
3247 ol("rr\tl");
3248 } else if ( value == 8 ) {
3249 if ( ulvalue(lval) ) { /* 3 bytes, 11T */
3250 ol("ld\tl,h");
3251 ol("ld\th,0");
3252 } else { /* 5 bytes, 20 T */
3253 ol("ld\tl,h");
3254 ol("ld\ta,h");
3255 ol("rlca");
3256 ol("sbc\ta");
3257 ol("ld\th,a");
3258 }
3259 } else if ( value == 15 && ulvalue(lval) && (c_cpu != CPU_Z80N && !IS_808x()) ) {
3260 ol("rl\th"); /* 7 bytes, 26T */
3261 vconst(0);
3262 ol("rl\tl");
3263 } else if ( value == 2 ) { /* 8 bytes, 32T */
3264 asr_const(lval, 1);
3265 asr_const(lval, 1);
3266 } else if ( value != 0 ) {
3267 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 22T
3268 ol("ex\tde,hl"); // 1, 4T
3269 outfmt("\tld\tb,%d\n", value & 15); // 2, 7T
3270 if ( ulvalue(lval) ) { // 2, 8T
3271 ol("bsrl\tde,b");
3272 } else {
3273 ol("bsra\tde,b");
3274 }
3275 ol("ex\tde,hl"); // 1, 4T
3276 } else {
3277 const2(value & 0xffff); /* 6 bytes */
3278 if ( ulvalue(lval))
3279 callrts("l_asr_u_hl_by_e");
3280 else
3281 callrts("l_asr_hl_by_e");
3282 }
3283 }
3284 }
3285 }
3286
3287
3288 /* Arithmetic left shift the secondary register number of */
3289 /* times in primary (results in primary) */
asl(LVALUE * lval)3290 void asl(LVALUE* lval)
3291 {
3292 switch (lval->val_type) {
3293 case KIND_LONGLONG:
3294 callrts("l_i64_asl");
3295 Zsp += 8;
3296 break;
3297 case KIND_LONG:
3298 case KIND_CPTR:
3299 callrts("l_long_asl");
3300 Zsp += 4;
3301 break;
3302 default:
3303 callrts("l_asl");
3304 }
3305 }
3306
asl_16bit_const(LVALUE * lval,int value)3307 void asl_16bit_const(LVALUE *lval, int value)
3308 {
3309 switch ( value ) {
3310 case 0:
3311 return;
3312 case 10: // 7 bytes, 8 + 8 + 4 + 7 = 27T
3313 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3314 ol("ex\tde,hl"); // 1, 4T
3315 ol("ld\tb,10"); // 2, 7T
3316 ol("bsla\tde,b"); // 2, 8T
3317 ol("ex\tde,hl"); // 1, 4T
3318 } else if ( !IS_808x()) {
3319 ol("sla\tl");
3320 ol("sla\tl");
3321 ol("ld\th,l");
3322 ol("ld\tl,0");
3323 } else {
3324 ol("ld\ta,l");
3325 ol("rlca");
3326 ol("rlca");
3327 ol("and\t252");
3328 ol("ld\th,a");
3329 ol("ld\tl,0");
3330 }
3331 break;
3332 case 9: // 6 bytes, 8 + 4 + 7 = 19T
3333 if ( IS_808x()) {
3334 ol("ld\ta,l");
3335 ol("and\ta");
3336 ol("rla");
3337 ol("ld\th,a");
3338 ol("ld\tl,0");
3339 } else {
3340 ol("sla\tl");
3341 ol("ld\th,l");
3342 ol("ld\tl,0");
3343 }
3344 break;
3345 case 8: // 3 bytes, 4 + 7 = 11T
3346 ol("ld\th,l");
3347 ol("ld\tl,0");
3348 break;
3349 case 7:
3350 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3351 ol("ex\tde,hl"); // 1, 4T
3352 ol("ld\tb,7"); // 2, 7T
3353 ol("bsla\tde,b"); // 2, 8T
3354 ol("ex\tde,hl"); // 1, 4T
3355 break;
3356 } else if ( c_speed_optimisation & OPT_LSHIFT32 && !IS_808x() ) {
3357 ol("rr\th"); // 9 bytes, 8 + 4 + 8 + 7 + 8 = 35T
3358 ol("ld\th,l");
3359 ol("rr\th");
3360 ol("ld\tl,0");
3361 ol("rr\tl");
3362 break;
3363 }
3364 ol("add\thl,hl"); // 77T
3365 case 6:
3366 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3367 ol("ex\tde,hl"); // 1, 4T
3368 ol("ld\tb,6"); // 2, 7T
3369 ol("bsla\tde,b"); // 2, 8T
3370 ol("ex\tde,hl"); // 1, 4T
3371 break;
3372 }
3373 ol("add\thl,hl"); // 66T
3374 // Fall through
3375 case 5: // 5 bytes, 55T
3376 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3377 ol("ex\tde,hl"); // 1, 4T
3378 ol("ld\tb,5"); // 2, 7T
3379 ol("bsla\tde,b"); // 2, 8T
3380 ol("ex\tde,hl"); // 1, 4T
3381 break;
3382 }
3383 ol("add\thl,hl"); // 55T
3384 case 4: // 4 bytes, 44T
3385 if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3386 ol("ex\tde,hl"); // 1, 4T
3387 ol("ld\tb,4"); // 2, 7T
3388 ol("bsla\tde,b"); // 2, 8T
3389 ol("ex\tde,hl"); // 1, 4T
3390 break;
3391 }
3392 ol("add\thl,hl"); // 44T
3393 case 3:
3394 ol("add\thl,hl"); // 33T
3395 case 2:
3396 ol("add\thl,hl"); // 22T
3397 case 1:
3398 ol("add\thl,hl"); // 11T
3399 break;
3400 default: // 7 bytes
3401 if ( value >= 16 ) {
3402 warningfmt("overflow","Left shifting by more than the size of the object");
3403 vconst(0);
3404 } else if ( c_cpu == CPU_Z80N ) { // 6 bytes, 23T
3405 ol("ex\tde,hl"); // 1, 4T
3406 outfmt("\tld\tb,%d\n", value & 15); // 2, 7T
3407 ol("bsla\tde,b"); // 2, 8T
3408 ol("ex\tde,hl"); // 1, 4T
3409 } else {
3410 const2(value & 0xffff);
3411 swap();
3412 callrts("l_asl");
3413 }
3414 break;
3415 }
3416 }
3417
asl_const(LVALUE * lval,int64_t value64)3418 void asl_const(LVALUE *lval, int64_t value64)
3419 {
3420 int32_t value = (int32_t)value64;
3421 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR ) {
3422 switch ( value ) {
3423 case 0:
3424 return;
3425 case 24: // 6 bytes, 4 + 7 + 10 = 21T
3426 ol("ld\td,l");
3427 ol("ld\te,0");
3428 vconst(0);
3429 break;
3430 case 18: // 6 btes
3431 ol("add\thl,hl");
3432 case 17: // 5 bytes
3433 ol("add\thl,hl"); // 5 bytes, 11 + 4 + 10 = 25T
3434 // Fall through
3435 case 16: // 4 bytes
3436 swap();
3437 vconst(0);
3438 break;
3439 case 8: // 5 bytes, 4 + 4 + 4 +7 = 19T
3440 ol("ld\td,e");
3441 ol("ld\te,h");
3442 ol("ld\th,l");
3443 ol("ld\tl,0");
3444 break;
3445 case 1: /* 5 bytes, 11 + 8 + 8 = 27T */
3446 ol("add\thl,hl");
3447 if ( IS_8085() ) {
3448 ol("rl\tde");
3449 } else if ( IS_8080() ) {
3450 ol("ld\ta,e");
3451 ol("rla");
3452 ol("ld\te,a");
3453 ol("ld\ta,d");
3454 ol("rla");
3455 ol("ld\td,a");
3456 } else {
3457 ol("rl\te");
3458 ol("rl\td");
3459 }
3460 break;
3461 case 7:
3462 if ( 0 && c_speed_optimisation & OPT_LSHIFT32) {
3463 ol("rr\td"); // 15 bytes, 59T
3464 ol("ld\td,e");
3465 ol("ld\te,h");
3466 ol("ld\th,l");
3467 ol("ld\tl,0");
3468 ol("rr\td");
3469 ol("rr\te");
3470 ol("rr\th");
3471 ol("rr\tl");
3472 } else {
3473 loada( value );
3474 callrts("l_long_aslo");
3475 }
3476 break;
3477 case 9:
3478 case 10:
3479 case 11:
3480 case 12:
3481 case 13:
3482 case 14:
3483 // Shift by 8, 10 bytes, 4 + 4 + 4+ 7 = 19T +
3484 ol("ld\td,e");
3485 ol("ld\te,h");
3486 ol("ld\th,l");
3487 ol("ld\tl,0");
3488 loada( value - 8 );
3489 callrts("l_long_aslo");
3490 break;
3491 default: // 5 bytes
3492 if ( value >= 32 ) warningfmt("overflow","Left shifting by more than the size of the object");
3493 value &= 31;
3494 if ( value >= 16 ) {
3495 asl_16bit_const(lval, value - 16);
3496 swap();
3497 ot("ld\thl,"); outdec(0); nl();
3498 } else {
3499 loada( value );
3500 callrts("l_long_aslo");
3501 }
3502 break;
3503 }
3504 } else if ( lval->val_type == KIND_LONGLONG ) {
3505 if ( value >= 64 ) warningfmt("overflow","Left shifting by more than the size of the object");
3506 llpush();
3507 loada(value & 63);
3508 callrts("l_i64_aslo");
3509 Zsp += 8;
3510 } else {
3511 asl_16bit_const(lval, value);
3512 }
3513 }
3514
3515
set_carry(LVALUE * lval)3516 static void set_carry(LVALUE *lval)
3517 {
3518 lval->val_type = KIND_CARRY;
3519 lval->ltype = type_carry;
3520 }
3521
set_int(LVALUE * lval)3522 static void set_int(LVALUE *lval)
3523 {
3524 lval->val_type = KIND_INT;
3525 lval->ltype = type_int;
3526 }
3527
3528 /* Form logical negation of primary register */
lneg(LVALUE * lval)3529 void lneg(LVALUE* lval)
3530 {
3531 lval->oldval_kind = lval->val_type;
3532 switch (lval->val_type) {
3533 case KIND_LONGLONG:
3534 callrts("l_i64_lneg");
3535 lval->val_type = KIND_INT;
3536 lval->ltype = type_int;
3537 break;
3538 case KIND_LONG:
3539 case KIND_CPTR:
3540 lval->val_type = KIND_INT;
3541 lval->ltype = type_int;
3542 callrts("l_long_lneg");
3543 break;
3544 case KIND_CARRY:
3545 set_carry(lval);
3546 ol("ccf");
3547 break;
3548 case KIND_DOUBLE:
3549 case KIND_FLOAT16:
3550 zconvert_from_double(lval->val_type,KIND_INT, 0);
3551 default:
3552 set_int(lval);
3553 callrts("l_lneg");
3554 }
3555 }
3556
3557 /* Form two's complement of primary register */
neg(LVALUE * lval)3558 void neg(LVALUE* lval)
3559 {
3560 switch (lval->val_type) {
3561 case KIND_LONGLONG:
3562 callrts("l_i64_neg");
3563 break;
3564 case KIND_LONG:
3565 case KIND_CPTR:
3566 callrts("l_long_neg");
3567 break;
3568 case KIND_FLOAT16:
3569 ol("ld\ta,h");
3570 ol("xor\t128");
3571 ol("ld\th,a");
3572 break;
3573 case KIND_DOUBLE:
3574 switch ( c_maths_mode ) {
3575 case MATHS_IEEE:
3576 ol("ld\ta,d");
3577 ol("xor\t128");
3578 ol("ld\td,a");
3579 break;
3580 case MATHS_MBFS:
3581 ol("ld\ta,e");
3582 ol("xor\t128");
3583 ol("ld\te,a");
3584 break;
3585 default:
3586 dcallrts("fnegate",KIND_DOUBLE);
3587 }
3588 break;
3589 default:
3590 callrts("l_neg");
3591 }
3592 }
3593
3594 /* Form one's complement of primary register */
com(LVALUE * lval)3595 void com(LVALUE* lval)
3596 {
3597 switch (lval->val_type) {
3598 case KIND_LONGLONG:
3599 callrts("l_i64_com");
3600 break;
3601 case KIND_LONG:
3602 case KIND_CPTR:
3603 callrts("l_long_com");
3604 break;
3605 default:
3606 callrts("l_com");
3607 }
3608 }
3609
3610
3611 /*
3612 * Increment value held in main register
3613 */
3614
inc(LVALUE * lval)3615 void inc(LVALUE* lval)
3616 {
3617 switch (lval->val_type) {
3618 case KIND_DOUBLE:
3619 // FA = value to be incremented
3620 gen_push_float(lval->val_type);
3621 switch ( c_maths_mode ) {
3622 case MATHS_IEEE:
3623 vlongconst(0x3f800000); // +1.0
3624 break;
3625 case MATHS_MBFS:
3626 vlongconst(0x81000000); // +1.0
3627 break;
3628 case MATHS_AM9511:
3629 vlongconst(0x01800000); // +1.0
3630 break;
3631 default:
3632 gen_load_constant_as_float(1, KIND_DOUBLE, 1);
3633 }
3634 dcallrts("fadd",KIND_DOUBLE);
3635 Zsp += c_fp_size;
3636 break;
3637 case KIND_FLOAT16:
3638 gen_push_float(lval->val_type);
3639 vconst(0x3c00); // +1.0
3640 dcallrts("fadd",KIND_FLOAT16);
3641 Zsp += 2;
3642 break;
3643 case KIND_LONGLONG:
3644 callrts("l_i64_inc");
3645 break;
3646 case KIND_LONG:
3647 case KIND_CPTR:
3648 callrts("l_inclong");
3649 break;
3650 default:
3651 ol("inc\thl");
3652 }
3653 }
3654
3655 /*
3656 * Decrement value held in main register
3657 */
3658
dec(LVALUE * lval)3659 void dec(LVALUE* lval)
3660 {
3661 switch (lval->val_type) {
3662 case KIND_DOUBLE:
3663 // FA = value to be incremented
3664 gen_push_float(lval->val_type);
3665 switch ( c_maths_mode ) {
3666 case MATHS_IEEE:
3667 vlongconst(0xbf800000); // -1.0
3668 break;
3669 case MATHS_MBFS:
3670 vlongconst(0x81800000); // -1.0
3671 break;
3672 case MATHS_AM9511:
3673 vlongconst(0x81800000); // -1.0
3674 break;
3675 default:
3676 gen_load_constant_as_float(-1,KIND_DOUBLE, 0);
3677 }
3678 callrts("fadd");
3679 Zsp += c_fp_size;
3680 break;
3681 case KIND_FLOAT16:
3682 gen_push_float(lval->val_type);
3683 vconst(0xbc00); // -1.0
3684 dcallrts("fadd",KIND_FLOAT16);
3685 Zsp += 2;
3686 break;
3687 case KIND_LONGLONG:
3688 callrts("l_i64_dec");
3689 break;
3690 case KIND_LONG:
3691 case KIND_CPTR:
3692 callrts("l_declong");
3693 break;
3694 default:
3695 ol("dec\thl");
3696 }
3697 }
3698
3699 /* Following are the conditional operators */
3700 /* They compare the secondary register against the primary */
3701 /* and put a literal 1 in the primary if the condition is */
3702 /* true, otherwise they clear the primary register */
3703
dummy(LVALUE * lval)3704 void dummy(LVALUE *lval)
3705 {
3706 /* Dummy function to allows us to check for c/nc at end of if clause */
3707 }
3708
3709 /* test for equal to zero */
eq0(LVALUE * lval,int label)3710 void eq0(LVALUE* lval, int label)
3711 {
3712 check_lastop_was_comparison(lval);
3713 switch (lval->val_type) {
3714 #ifdef CHARCOMP0
3715 case KIND_CHAR:
3716 ol("ld\ta,l");
3717 ol("and\ta");
3718 break;
3719 #endif
3720 case KIND_LONGLONG:
3721 callrts("l_i64_eq0");
3722 break;
3723 case KIND_LONG:
3724 ol("ld\ta,h");
3725 ol("or\tl");
3726 ol("or\td");
3727 ol("or\te");
3728 break;
3729 case KIND_CPTR:
3730 ol("ld\ta,e");
3731 ol("or\th");
3732 ol("or\tl");
3733 break;
3734 default:
3735 ol("ld\ta,h");
3736 ol("or\tl");
3737 }
3738 opjump("nz,", label);
3739 }
3740
3741
3742
zeq_const(LVALUE * lval,int64_t value64)3743 void zeq_const(LVALUE *lval, int64_t value64)
3744 {
3745 int32_t value = (int32_t)value64;
3746 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
3747 if ( value == 0 ) {
3748 if ( lval->val_type == KIND_CPTR) {
3749 ol("ld\ta,e");
3750 } else {
3751 ol("ld\ta,d");
3752 ol("or\te");
3753 }
3754 ol("or\th");
3755 ol("or\tl");
3756 if ( IS_808x() ) {
3757 ol("jp\tnz,ASMPC+4");
3758 } else {
3759 ol("jr\tnz,ASMPC+3"); // 2, 12/7
3760 }
3761 ol("scf");
3762 set_carry(lval);
3763 } else if ( c_speed_optimisation & OPT_LONG_COMPARE && !IS_8080() && !IS_GBZ80() ) {
3764 constbc(value % 65536); // 18 bytes or 14 with zero top word
3765 ol("and\ta");
3766 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
3767 if ( value / 65536 == 0 ) {
3768 ol("jr\tnz,ASMPC+7");
3769 ol("ld\ta,d");
3770 ol("or\te");
3771 ol("scf");
3772 ol("jr\tz,ASMPC+3");
3773 ol("and\ta");
3774 } else {
3775 ol("jr\tnz,ASMPC+11");
3776 ol("ex\tde,hl");
3777 constbc(value / 65536);
3778 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
3779 ol("scf");
3780 ol("jr\tz,ASMPC+3");
3781 ol("and\ta");
3782 }
3783 set_carry(lval);
3784 } else {
3785 lpush(); // 11 bytes
3786 vlongconst(value);
3787 zeq(lval);
3788 }
3789 } else if ( lval->val_type == KIND_CHAR ) {
3790 if ( value == 0 ) {
3791 ol("ld\ta,l"); // 5 bytes
3792 ol("and\ta");
3793 if ( IS_808x() ) {
3794 ol("jp\tnz,ASMPC+4");
3795 } else {
3796 ol("jr\tnz,ASMPC+3");
3797 }
3798 ol("scf");
3799 } else {
3800 ol("ld\ta,l"); // 7 bytes
3801 outfmt("\tcp\t%d\n", (value % 256));
3802 ol("scf");
3803 if ( IS_808x() ) {
3804 ol("jp\tz,ASMPC+4");
3805 } else {
3806 ol("jr\tz,ASMPC+3");
3807 }
3808 ol("ccf");
3809 }
3810 set_carry(lval);
3811 } else if ( lval->val_type == KIND_LONGLONG) {
3812 llpush();
3813 vllongconst(value64);
3814 zeq(lval);
3815 } else {
3816 if ( value == 0 ) {
3817 ol("ld\ta,h");
3818 ol("or\tl");
3819 if ( IS_808x() ) {
3820 ol("jp\tnz,ASMPC+4");
3821 } else {
3822 ol("jr\tnz,ASMPC+3");
3823 }
3824 ol("scf");
3825 set_carry(lval);
3826 } else if ( IS_808x() || IS_GBZ80() ) {
3827 const2(value & 0xffff);
3828 callrts("l_eq");
3829 set_int(lval);
3830 } else {
3831 const2(value & 0xffff); // 10 bytes
3832 ol("and\ta");
3833 ol("sbc\thl,de");
3834 ol("scf");
3835 ol("jr\tz,ASMPC+3");
3836 ol("ccf");
3837 set_carry(lval);
3838 }
3839 }
3840 }
3841
3842 /* Test for equal */
zeq(LVALUE * lval)3843 void zeq(LVALUE* lval)
3844 {
3845 lval->oldval_kind = lval->val_type;
3846 lval->ptr_type = KIND_NONE;
3847 switch (lval->val_type) {
3848 case KIND_LONGLONG:
3849 callrts("l_i64_eq");
3850 Zsp += 8;
3851 set_int(lval);
3852 break;
3853 case KIND_LONG:
3854 case KIND_CPTR:
3855 set_int(lval);
3856 callrts("l_long_eq");
3857 Zsp += 4;
3858 break;
3859 case KIND_FLOAT16:
3860 dcallrts("feq",lval->val_type);
3861 set_int(lval);
3862 Zsp += 2;
3863 break;
3864 case KIND_DOUBLE:
3865 set_int(lval);
3866 dcallrts("feq",lval->val_type);
3867 Zsp += c_fp_size;
3868 break;
3869 case KIND_CHAR:
3870 if (c_speed_optimisation & OPT_CHAR_COMPARE ) {
3871 set_carry(lval);
3872 ol("ld\ta,l");
3873 ol("sub\te");
3874 ol("and\ta");
3875 if ( IS_808x() ) {
3876 ol("jp\tnz,ASMPC+4");
3877 } else {
3878 ol("jr\tnz,ASMPC+3");
3879 }
3880 ol("scf");
3881 break;
3882 }
3883 default:
3884 if ( c_speed_optimisation & OPT_INT_COMPARE && !IS_808x() && !IS_GBZ80() ) {
3885 ol("and\ta");
3886 ol("sbc\thl,de");
3887 ol("scf");
3888 ol("jr\tz,ASMPC+3");
3889 ol("ccf");
3890 set_carry(lval);
3891 } else {
3892 set_int(lval);
3893 callrts("l_eq");
3894 }
3895 }
3896 }
3897
zne_const(LVALUE * lval,int64_t value64)3898 void zne_const(LVALUE *lval, int64_t value64)
3899 {
3900 int32_t value = (int32_t)value64;
3901 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
3902 if ( value == 0 ) {
3903 if ( lval->val_type == KIND_CPTR) {
3904 ol("ld\ta,e");
3905 } else {
3906 ol("ld\ta,d");
3907 ol("or\te");
3908 }
3909 ol("or\th");
3910 ol("or\tl");
3911 if ( IS_808x() ) {
3912 ol("jp\tz,ASMPC+4");
3913 } else {
3914 ol("jr\tz,ASMPC+3");
3915 }
3916 ol("scf");
3917 set_carry(lval);
3918 } else {
3919 if ( c_speed_optimisation & OPT_LONG_COMPARE && !IS_8080() && !IS_GBZ80() ) {
3920 ol("and\ta"); // 18 bytes, 14 bytes if zero top word
3921 constbc(value % 65536);
3922 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
3923 if ( value / 65536 == 0 ) {
3924 ol("jr\tnz,ASMPC+4"); // into scf
3925 ol("ld\ta,d");
3926 ol("or\te");
3927 ol("scf");
3928 ol("jr\tnz,ASMPC+3");
3929 ol("and\ta");
3930 } else {
3931 ol("jr\tnz,ASMPC+8"); // into scf
3932 // Carry should still be reset if zero
3933 swap();
3934 constbc(value / 65536);
3935 if ( IS_8085() ) ol("sub\thl,bc"); else ol("sbc\thl,bc");
3936 ol("scf");
3937 ol("jr\tnz,ASMPC+3"); // into scf§
3938 ol("and\ta"); // Reset carry
3939 set_carry(lval);
3940 }
3941 } else {
3942 lpush(); // 11 bytes
3943 vlongconst(value);
3944 zne(lval);
3945 }
3946 }
3947 } else if ( lval->val_type == KIND_CHAR ) {
3948 if ( value == 0 ) {
3949 ol("ld\ta,l"); // 5 bytes
3950 ol("and\ta");
3951 if ( IS_808x() ) {
3952 ol("jp\tz,ASMPC+4");
3953 } else {
3954 ol("jr\tz,ASMPC+3");
3955 }
3956 ol("scf");
3957 } else {
3958 ol("ld\ta,l"); // 6 bytes
3959 outfmt("\tcp\t%d\n", (value % 256)); /* z = 1, c = 0 */
3960 if ( IS_808x() ) {
3961 ol("jp\tz,ASMPC+4");
3962 } else {
3963 ol("jr\tz,ASMPC+3");
3964 }
3965 ol("scf");
3966 }
3967 set_carry(lval);
3968 } else if ( lval->val_type == KIND_LONGLONG) {
3969 llpush();
3970 vllongconst(value64);
3971 zne(lval);
3972 } else {
3973 if ( value == 0 ) {
3974 ol("ld\ta,h");
3975 ol("or\tl");
3976 if ( IS_808x() ) {
3977 ol("jp\tz,ASMPC+4");
3978 } else {
3979 ol("jr\tz,ASMPC+3");
3980 }
3981 ol("scf");
3982 } else if ( IS_808x() || IS_GBZ80() ) {
3983 const2(value & 0xffff);
3984 callrts("l_ne");
3985 set_int(lval);
3986 } else {
3987 const2(value & 0xffff); // 10 bytes
3988 ol("and\ta");
3989 ol("sbc\thl,de");
3990 ol("scf");
3991 ol("jr\tnz,ASMPC+3");
3992 ol("ccf");
3993 }
3994 set_carry(lval);
3995 }
3996 }
3997
3998 /* Test for not equal */
zne(LVALUE * lval)3999 void zne(LVALUE* lval)
4000 {
4001 lval->oldval_kind = lval->val_type;
4002 lval->ptr_type = KIND_NONE;
4003 switch (lval->val_type) {
4004 case KIND_LONGLONG:
4005 callrts("l_i64_ne");
4006 Zsp += 8;
4007 set_int(lval);
4008 break;
4009 case KIND_LONG:
4010 case KIND_CPTR:
4011 set_int(lval);
4012 callrts("l_long_ne");
4013 Zsp += 4;
4014 break;
4015 case KIND_FLOAT16:
4016 dcallrts("fne",lval->val_type);
4017 set_int(lval);
4018 Zsp += 2;
4019 break;
4020 case KIND_DOUBLE:
4021 dcallrts("fne",lval->val_type);
4022 set_int(lval);
4023 Zsp += c_fp_size;
4024 break;
4025 case KIND_CHAR:
4026 if (c_speed_optimisation & OPT_CHAR_COMPARE ) {
4027 set_carry(lval);
4028 ol("ld\ta,l");
4029 ol("sub\te");
4030 ol("and\ta");
4031 if ( IS_808x() ) {
4032 ol("jp\tz,ASMPC+4");
4033 } else {
4034 ol("jr\tz,ASMPC+3");
4035 }
4036 ol("scf");
4037 break;
4038 }
4039 default:
4040 if ( c_speed_optimisation & OPT_INT_COMPARE && !IS_808x() && !IS_GBZ80() ) {
4041 ol("and\ta"); // 7 bytes
4042 ol("sbc\thl,de");
4043 ol("scf");
4044 ol("jr\tnz,ASMPC+3");
4045 ol("ccf");
4046 set_carry(lval);
4047 } else {
4048 set_int(lval);
4049 callrts("l_ne");
4050 }
4051 }
4052 }
4053
4054
zlt_const(LVALUE * lval,int64_t value64)4055 void zlt_const(LVALUE *lval, int64_t value64)
4056 {
4057 int32_t value = (int32_t)value64;
4058 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
4059 if ( value == 0 ) {
4060 if ( ulvalue(lval) ) {
4061 ol("and\ta"); // Should not reach here
4062 } else {
4063 ol("ld\ta,d");
4064 ol("rla");
4065 }
4066 set_carry(lval);
4067 } else if ( !IS_808x() ) {
4068 ol("ld\ta,l"); // 12 bytes (unsigned), 15 bytes (signed) vs 11 bytes + call
4069 outfmt("\tsub\t%d\n", (value % 65536) % 256);
4070 ol("ld\ta,h");
4071 outfmt("\tsbc\t%d\n", (value % 65536) / 256);
4072 ol("ld\ta,e");
4073 outfmt("\tsbc\t%d\n", (value / 65536) % 256);
4074 ol("ld\ta,d");
4075 if ( ulvalue(lval)) {
4076 outfmt("\tsbc\t%d\n", (value / 65536) / 256);
4077 } else {
4078 ol("rla");
4079 ol("ccf");
4080 ol("rra");
4081 outfmt("\tsbc\t%d\n", (0x80 + ((uint32_t)(value /65536) / 256)) & 0xff);
4082 }
4083 set_carry(lval);
4084 } else {
4085 lpush();
4086 vlongconst(value);
4087 callrts("l_long_lt");
4088 set_int(lval);
4089 Zsp += 4;
4090 }
4091 } else if ( lval->val_type == KIND_CHAR && ulvalue(lval)) {
4092 if ( value == 0 ) {
4093 ol("and\ta");
4094 } else {
4095 ol("ld\ta,l");
4096 outfmt("\tsub\t%d\n", (value % 256));
4097 }
4098 set_carry(lval);
4099 } else if ( lval->val_type == KIND_CHAR) {
4100 // We're signed here
4101 if ( value == 0 ) {
4102 ol("ld\ta,l");
4103 ol("rla");
4104 } else {
4105 ol("ld\ta,l");
4106 outfmt("\tsub\t%d\n", (value % 256));
4107 }
4108 set_carry(lval);
4109 } else if ( lval->val_type == KIND_INT || lval->val_type == KIND_PTR ) {
4110 if ( value == 0 ) {
4111 if ( ulvalue(lval) ) {
4112 ol("and\ta"); // Should not reach here
4113 set_carry(lval);
4114 } else {
4115 ol("ld\ta,h");
4116 ol("rla");
4117 set_carry(lval);
4118 }
4119 } else {
4120 if ( ulvalue(lval)) {
4121 if ( IS_808x() || IS_GBZ80() ) {
4122 ol("ld\ta,l"); // 6 bytes
4123 outfmt("\tsub\t%d\n", ((uint32_t)value % 256) & 0xff);
4124 ol("ld\ta,h");
4125 outfmt("\tsbc\t%d\n", ((uint32_t)value / 256) & 0xff);
4126 set_carry(lval);
4127 } else {
4128 const2(value & 0xffff); // 6 bytes
4129 ol("and\ta");
4130 ol("sbc\thl,de");
4131 set_carry(lval);
4132 }
4133 } else {
4134 ol("ld\ta,l"); // 9 bytesz
4135 outfmt("\tsub\t%d\n", ((uint32_t)value % 256) & 0xff);
4136 ol("ld\ta,h");
4137 ol("rla");
4138 ol("ccf");
4139 ol("rra");
4140 outfmt("\tsbc\t%d\n", (0x80 + ((uint32_t)value / 256)) & 0xff);
4141 set_carry(lval);
4142 }
4143 }
4144 } else if ( lval->val_type == KIND_LONGLONG) {
4145 llpush();
4146 vllongconst(value64);
4147 zlt(lval);
4148 } else {
4149 const2(value & 0xffff); // 7 bytes
4150 swap();
4151 zlt(lval);
4152 }
4153 }
4154
4155 /* Test for less than*/
zlt(LVALUE * lval)4156 void zlt(LVALUE* lval)
4157 {
4158 lval->oldval_kind = lval->val_type;
4159 lval->ptr_type = KIND_NONE;
4160 switch (lval->val_type) {
4161 case KIND_LONGLONG:
4162 if (ulvalue(lval))
4163 callrts("l_i64_ult");
4164 else
4165 callrts("l_i64_lt");
4166 set_int(lval);
4167 Zsp += 8;
4168 break;
4169 case KIND_LONG:
4170 case KIND_CPTR:
4171 if (ulvalue(lval))
4172 callrts("l_long_ult");
4173 else
4174 callrts("l_long_lt");
4175 Zsp += 4;
4176 set_int(lval);
4177 break;
4178 case KIND_FLOAT16:
4179 dcallrts("flt",lval->val_type);
4180 set_int(lval);
4181 Zsp += 2;
4182 break;
4183 case KIND_DOUBLE:
4184 dcallrts("flt",lval->val_type);
4185 set_int(lval);
4186 Zsp += c_fp_size;
4187 break;
4188 case KIND_CHAR:
4189 if (c_speed_optimisation & OPT_CHAR_COMPARE ) {
4190 if (ulvalue(lval)) {
4191 ol("ld\ta,e");
4192 ol("sub\tl");
4193 } else {
4194 ol("ld\ta,e");
4195 ol("sub\tl");
4196 ol("rra");
4197 ol("xor\te");
4198 ol("xor\tl");
4199 ol("rlca");
4200 }
4201 set_carry(lval);
4202 break;
4203 }
4204 default:
4205 if (ulvalue(lval)) {
4206 if ( IS_808x() || IS_GBZ80() ) {
4207 ol("ld\ta,e");
4208 ol("sub\tl");
4209 ol("ld\ta,d");
4210 ol("sbc\th");
4211 set_carry(lval);
4212 } else {
4213 // callrts("l_ult");
4214 // de = lhs, hl = rhs
4215 swap();
4216 ol("and\ta");
4217 ol("sbc\thl,de");
4218 set_carry(lval);
4219 }
4220 } else {
4221 callrts("l_lt");
4222 set_int(lval);
4223 }
4224 }
4225 }
4226
4227
4228
zle_const(LVALUE * lval,int64_t value64)4229 void zle_const(LVALUE *lval, int64_t value64)
4230 {
4231 int32_t value = (int32_t)value64;
4232 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
4233 if ( value == 0 && !IS_808x() ) {
4234 if ( lval->val_type == KIND_CPTR) {
4235 ol("ld\ta,e");
4236 } else {
4237 ol("ld\ta,d");
4238 if ( !ulvalue(lval)) {
4239 ol("rla");
4240 ol("jr\tc,ASMPC+8");
4241 }
4242 ol("or\te"); // We know MSBit was 0, so no point shifting it back in
4243 }
4244 ol("or\th");
4245 ol("or\tl");
4246 ol("jr\tnz,ASMPC+3");
4247 ol("scf");
4248 set_carry(lval);
4249 } else {
4250 lpush(); // 11 bytes
4251 vlongconst(value);
4252 zle(lval);
4253 }
4254 } else if ( lval->val_type == KIND_CHAR && ulvalue(lval)) {
4255 outfmt("\tld\ta,%d\n", (value % 256));
4256 ol("sub\tl");
4257 ol("ccf");
4258 set_carry(lval);
4259 } else if ( lval->val_type == KIND_LONGLONG) {
4260 llpush();
4261 vllongconst(value64);
4262 zle(lval);
4263 } else {
4264 if ( value == 0 && !IS_808x() ) {
4265 ol("ld\ta,h"); // 8 bytes
4266 ol("rla");
4267 ol("jr\tc,ASMPC+6");
4268 ol("or\tl"); // We know MSBit was 0, so no point shifting it back in
4269 ol("jr\tnz,ASMPC+3");
4270 ol("scf");
4271 set_carry(lval);
4272 } else {
4273 const2(value & 0xffff); // 7 bytes
4274 swap();
4275 zle(lval);
4276 }
4277 }
4278 }
4279
4280 /* Test for less than or equal to (signed/unsigned) */
zle(LVALUE * lval)4281 void zle(LVALUE* lval)
4282 {
4283 lval->oldval_kind = lval->val_type;
4284 lval->ptr_type = KIND_NONE;
4285 switch (lval->val_type) {
4286 case KIND_LONGLONG:
4287 if (ulvalue(lval))
4288 callrts("l_i64_ule");
4289 else
4290 callrts("l_i64_le");
4291 set_int(lval);
4292 Zsp += 8;
4293 break;
4294 case KIND_LONG:
4295 case KIND_CPTR:
4296 if (ulvalue(lval))
4297 callrts("l_long_ule");
4298 else
4299 callrts("l_long_le");
4300 set_int(lval);
4301 Zsp += 4;
4302 break;
4303 case KIND_FLOAT16:
4304 dcallrts("fle",lval->val_type);
4305 set_int(lval);
4306 Zsp += 2;
4307 break;
4308 case KIND_DOUBLE:
4309 dcallrts("fle",lval->val_type);
4310 set_int(lval);
4311 Zsp += c_fp_size;
4312 break;
4313 case KIND_CHAR:
4314 if (c_speed_optimisation & OPT_CHAR_COMPARE && !IS_808x()) {
4315 if (ulvalue(lval)) { /* unsigned */
4316 ol("ld\ta,e");
4317 ol("sub\tl"); /* If l < e then carry clear */
4318 ol("jr\tnz,ASMPC+3"); /* If zero, then set carry */
4319 ol("scf");
4320 } else {
4321 int label = getlabel();
4322 ol("ld\ta,e");
4323 ol("sub\tl");
4324 ol("rra");
4325 ol("scf");
4326 opjumpr("z,", label);
4327 ol("xor\te");
4328 ol("xor\tl");
4329 ol("rlca");
4330 postlabel(label);
4331 }
4332 set_carry(lval);
4333 break;
4334 }
4335 default:
4336 if (ulvalue(lval)) {
4337 if ( IS_808x() || IS_GBZ80() ) {
4338 ol("ld\ta,l");
4339 ol("sub\te");
4340 ol("ld\ta,h");
4341 ol("sbc\td");
4342 ol("ccf");
4343 set_carry(lval);
4344 } else {
4345 // de = lhs, hl = rhs
4346 ol("and\ta");
4347 ol("sbc\thl,de");
4348 ol("ccf");
4349 set_carry(lval);
4350 }
4351 // callrts("l_ule");
4352 } else {
4353 callrts("l_le");
4354 set_int(lval);
4355 }
4356 }
4357 }
4358
zgt_const(LVALUE * lval,int64_t value64)4359 void zgt_const(LVALUE *lval, int64_t value64)
4360 {
4361 int32_t value = (int32_t)value64;
4362 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
4363 if ( value == 0 && ulvalue(lval) ) {
4364 if ( lval->val_type == KIND_CPTR ) {
4365 ol("ld\ta,e");
4366 } else {
4367 ol("ld\ta,d");
4368 ol("or\te");
4369 }
4370 ol("or\th");
4371 ol("or\tl");
4372 if ( IS_808x() ) {
4373 ol("jp\tz,ASMPC+4");
4374 } else {
4375 ol("jr\tz,ASMPC+3");
4376 }
4377 ol("scf");
4378 set_carry(lval);
4379 } else {
4380 lpush();
4381 vlongconst(value);
4382 zgt(lval);
4383 }
4384 } else if ( lval->val_type == KIND_CHAR && ulvalue(lval)) {
4385 outfmt("\tld\ta,%d\n", (value % 256));
4386 ol("sub\tl");
4387 set_carry(lval);
4388 } else if ( value == 0 && lval->val_type == KIND_INT && ulvalue(lval)) {
4389 ol("ld\ta,h");
4390 ol("or\tl");
4391 if ( IS_808x() ) {
4392 ol("jp\tz,ASMPC+4");
4393 } else {
4394 ol("jr\tz,ASMPC+3");
4395 }
4396 ol("scf");
4397 set_carry(lval);
4398 } else if ( lval->val_type == KIND_LONGLONG) {
4399 llpush();
4400 vllongconst(value64);
4401 zgt(lval);
4402 } else {
4403 const2(value & 0xffff); // 7 bytes
4404 swap();
4405 zgt(lval);
4406 }
4407 }
4408
4409 /* Test for greater than (signed/unsigned) */
zgt(LVALUE * lval)4410 void zgt(LVALUE* lval)
4411 {
4412 lval->oldval_kind = lval->val_type;
4413 lval->ptr_type = KIND_NONE;
4414 switch (lval->val_type) {
4415 case KIND_LONGLONG:
4416 if (ulvalue(lval))
4417 callrts("l_i64_ugt");
4418 else
4419 callrts("l_i64_gt");
4420 set_int(lval);
4421 Zsp += 8;
4422 break;
4423 case KIND_LONG:
4424 case KIND_CPTR:
4425 if (ulvalue(lval))
4426 callrts("l_long_ugt");
4427 else
4428 callrts("l_long_gt");
4429 set_int(lval);
4430 Zsp += 4;
4431 break;
4432 case KIND_FLOAT16:
4433 dcallrts("fgt",lval->val_type);
4434 set_int(lval);
4435 Zsp += 2;
4436 break;
4437 case KIND_DOUBLE:
4438 dcallrts("fgt",lval->val_type);
4439 Zsp += c_fp_size;
4440 set_int(lval);
4441 break;
4442 case KIND_CHAR:
4443 if (c_speed_optimisation & OPT_CHAR_COMPARE ) {
4444 if (ulvalue(lval)) {
4445 ol("ld\ta,l");
4446 ol("sub\te");
4447 } else {
4448 ol("ld\ta,l");
4449 ol("sub\te");
4450 ol("rra");
4451 ol("xor\te");
4452 ol("xor\tl");
4453 ol("rlca");
4454 }
4455 set_carry(lval);
4456 break;
4457 }
4458 default:
4459 if (ulvalue(lval)) {
4460 if ( IS_808x() || IS_GBZ80() ) {
4461 outfmt("\tld\ta,e\n");
4462 ol("ld\ta,l");
4463 ol("sub\te");
4464 ol("ld\ta,h");
4465 ol("sbc\td");
4466 set_carry(lval);
4467 } else {
4468 ol("and\ta");
4469 ol("sbc\thl,de");
4470 set_carry(lval);
4471 }
4472 // callrts("l_ugt");
4473 } else {
4474 callrts("l_gt");
4475 set_int(lval);
4476 }
4477 }
4478 }
4479
4480
zge_const(LVALUE * lval,int64_t value64)4481 void zge_const(LVALUE *lval, int64_t value64)
4482 {
4483 int32_t value = (int32_t)value64;
4484 if ( lval->val_type == KIND_LONG || lval->val_type == KIND_CPTR) {
4485 if ( value == 0 ) {
4486 if ( ulvalue(lval) ) {
4487 ol("scf");
4488 } else {
4489 ol("ld\ta,d");
4490 ol("rla");
4491 ol("ccf");
4492 }
4493 set_carry(lval);
4494 return;
4495 }
4496 lpush();
4497 vlongconst(value);
4498 zge(lval);
4499 } else if ( lval->val_type == KIND_CHAR ) {
4500 if ( ulvalue(lval) ) {
4501 ol("ld\ta,l");
4502 outfmt("\tsub\t%d\n", (value % 256));
4503 ol("ccf");
4504 set_carry(lval);
4505 } else {
4506 ol("ld\ta,l");
4507 ol("xor\t128");
4508 outfmt("\tsub\t%d\n", 0x80 + ( value % 256));
4509 ol("ccf");
4510 }
4511 } else if ( lval->val_type == KIND_LONGLONG) {
4512 llpush();
4513 vllongconst(value64);
4514 zge(lval);
4515 } else {
4516 if ( value == 0 ) {
4517 if ( ulvalue(lval) ) {
4518 ol("scf"); // Should not reach here
4519 } else {
4520 ol("ld\ta,h");
4521 ol("rla");
4522 ol("ccf");
4523 }
4524 set_carry(lval);
4525 } else {
4526 if ( value == 0 ) {
4527 if ( ulvalue(lval) ) {
4528 ol("scf"); // Should not reach here
4529 } else {
4530 ol("ld\ta,h");
4531 ol("rla");
4532 ol("ccf");
4533 }
4534 set_carry(lval);
4535 } else {
4536 const2(value & 0xffff); // 7 bytes
4537 swap();
4538 zge(lval);
4539 }
4540 }
4541 }
4542 }
4543
4544 /* Test for greater than or equal to */
zge(LVALUE * lval)4545 void zge(LVALUE* lval)
4546 {
4547 lval->oldval_kind = lval->val_type;
4548 lval->ptr_type = KIND_NONE;
4549 switch (lval->val_type) {
4550 case KIND_LONGLONG:
4551 if (ulvalue(lval))
4552 callrts("l_i64_uge");
4553 else
4554 callrts("l_i64_ge");
4555 set_int(lval);
4556 Zsp += 8;
4557 break;
4558 case KIND_LONG:
4559 case KIND_CPTR:
4560 if (ulvalue(lval))
4561 callrts("l_long_uge");
4562 else
4563 callrts("l_long_ge");
4564 Zsp += 4;
4565 set_int(lval);
4566 break;
4567 case KIND_FLOAT16:
4568 dcallrts("fge",lval->val_type);
4569 set_int(lval);
4570 Zsp += 2;
4571 break;
4572 case KIND_DOUBLE:
4573 dcallrts("fge",lval->val_type);
4574 set_int(lval);
4575 Zsp += c_fp_size;
4576 break;
4577 case KIND_CHAR:
4578 if (c_speed_optimisation & OPT_CHAR_COMPARE && !IS_808x()) {
4579 if (ulvalue(lval)) {
4580 ol("ld\ta,l");
4581 ol("sub\te"); /* If e (RHS) > l, carry set */
4582 ol("jr\tnz,ASMPC+3"); /* If l == e then we need to set carry */
4583 ol("scf");
4584 } else {
4585 int label = getlabel();
4586 ol("ld\ta,e");
4587 ol("sub\tl");
4588 ol("rra");
4589 ol("scf");
4590 opjumpr("z,", label);
4591 ol("xor\te");
4592 ol("xor\tl");
4593 ol("rlca");
4594 ol("ccf");
4595 postlabel(label);
4596 }
4597 set_carry(lval);
4598 break;
4599 }
4600 default:
4601 if (ulvalue(lval)) {
4602 if ( c_speed_optimisation & OPT_INT_COMPARE && !IS_808x() && !IS_GBZ80() ) {
4603 swap();
4604 ol("and\ta");
4605 ol("sbc\thl,de");
4606 ol("ccf");
4607 set_carry(lval);
4608 } else {
4609 callrts("l_uge");
4610 set_int(lval);
4611 }
4612 } else {
4613 callrts("l_ge");
4614 set_int(lval);
4615 }
4616 }
4617 }
4618
4619
4620 /*
4621 * Routines for conversion between different types, kept in this
4622 * file to aid conversion etc
4623 */
4624
4625
gen_conv_carry2int(void)4626 void gen_conv_carry2int(void)
4627 {
4628 vconst(0);
4629 if ( !IS_808x() ) {
4630 ol("rl\tl");
4631 } else {
4632 ol("ld\ta,0");
4633 ol("rla");
4634 ol("ld\tl,a");
4635 }
4636 }
4637
gen_conv_uint2char(void)4638 void gen_conv_uint2char(void)
4639 {
4640 ol("ld\th,0");
4641 }
4642
gen_conv_sint2char(void)4643 void gen_conv_sint2char(void)
4644 {
4645 ol("ld\ta,l");
4646 callrts("l_sxt");
4647 }
4648
4649 /* Unsigned int to long */
gen_conv_uint2long(void)4650 void gen_conv_uint2long(void)
4651 {
4652 const2(0);
4653 }
4654
4655 /* Signed int to long */
gen_conv_sint2long(void)4656 void gen_conv_sint2long(void)
4657 {
4658 // ol("ld\ta,h");
4659 // ol("rla");
4660 // ol("sbc\ta");
4661 // ol("ld\te,a");
4662 // ol("ld\td,a");
4663 callrts("l_int2long_s");
4664 }
4665
4666
4667
4668 /* Swap double positions on stack */
gen_swap_float(Kind type)4669 void gen_swap_float(Kind type)
4670 {
4671 if (type == KIND_FLOAT16) {
4672 ol("ex\t(sp),hl");
4673 } else {
4674 callrts("fswap");
4675 }
4676 }
4677
vlongconst(zdouble val)4678 void vlongconst(zdouble val)
4679 {
4680 uint32_t l = (uint32_t)(int64_t)val;
4681 vconst(l % 65536);
4682 const2(l / 65536);
4683 }
4684
vllongconst(zdouble val)4685 void vllongconst(zdouble val)
4686 {
4687 load_llong_into_acc(val);
4688 }
4689
4690
vlongconst_tostack(zdouble val)4691 void vlongconst_tostack(zdouble val)
4692 {
4693 uint32_t l = (uint32_t)(int64_t)val;
4694 constbc(l / 65536);
4695 ol("push\tbc");
4696 constbc(l % 65536);
4697 ol("push\tbc");
4698 Zsp -= 4;
4699 }
4700
vllongconst_tostack(zdouble val)4701 void vllongconst_tostack(zdouble val)
4702 {
4703 uint64_t v,l;
4704
4705 v = val;
4706
4707 l = (v >> 32) & 0xffffffff;
4708 constbc(l / 65536);
4709 push("bc");
4710 constbc(l % 65536);
4711 push("bc");
4712
4713 l = v & 0xffffffff;
4714 constbc(l / 65536);
4715 push("bc");
4716 constbc(l % 65536);
4717 push("bc");
4718 }
4719
4720
4721 /*
4722 * load constant into primary register
4723 */
vconst(int64_t val)4724 void vconst(int64_t val)
4725 {
4726 if (val < 0)
4727 val += 65536;
4728 immed();
4729 outdec(val % 65536);
4730 ot(";const\n");
4731 }
4732
4733 /*
4734 * load constant into secondary register
4735 */
const2(int32_t val)4736 void const2(int32_t val)
4737 {
4738 if (val < 0)
4739 val += 65536;
4740 immed2();
4741 outdec(val);
4742 nl();
4743 }
4744
constbc(int32_t val)4745 void constbc(int32_t val)
4746 {
4747 if (val < 0)
4748 val += 65536;
4749 ot("ld\tbc,");
4750 outdec(val);
4751 nl();
4752 }
4753
addbchl(int val)4754 void addbchl(int val)
4755 {
4756 if ( c_cpu == CPU_Z80N ) {
4757 ot("add\thl,");
4758 outdec(val); nl();
4759 } else {
4760 ot("ld\tbc,");
4761 outdec(val);
4762 outstr("\n\tadd\thl,bc\n");
4763 }
4764 }
4765
4766
4767
4768 /*
4769 * Print prefix for global defintion
4770 */
4771
GlobalPrefix(void)4772 void GlobalPrefix(void)
4773 {
4774 ot("GLOBAL\t");
4775 }
4776
4777
4778 /*
4779 * Emit a LINE opcode for assembler
4780 * error reporting
4781 */
4782
gen_emit_line(int line)4783 void gen_emit_line(int line)
4784 {
4785 char filen[FILENAME_LEN];
4786 char *ptr;
4787
4788 snprintf(filen, sizeof(filen),"%s", Filename[0] == '\"'? Filename + 1 : Filename);
4789 if ( (ptr = strrchr(filen,'\"')) != NULL ) {
4790 *ptr = 0;
4791 }
4792
4793 if ( currfn ) {
4794 outfmt("\tC_LINE\t%d,\"%s::%s\"\n", line, filen,currfn->name);
4795 } else {
4796 outfmt("\tC_LINE\t%d,\"%s\"\n", line, filen);
4797 }
4798 }
4799
4800
4801
4802 /* Prefix for assembler */
4803
prefix()4804 void prefix()
4805 {
4806 outbyte('.');
4807 }
4808
4809 /* Print specified number as label */
printlabel(int label)4810 void printlabel(int label)
4811 {
4812 outfmt("i_%d", label);
4813 }
4814
4815 /* Print a label suffix */
col()4816 void col()
4817 {
4818 //outstr(":");
4819 }
4820
function_appendix(SYMBOL * func)4821 void function_appendix(SYMBOL* func)
4822 {
4823 }
4824
gen_switch_section(const char * section_name)4825 void gen_switch_section(const char* section_name)
4826 {
4827 /* If the same section don't do anything */
4828 if (strcmp(section_name, current_section) == 0) {
4829 return;
4830 }
4831 outfmt("\tSECTION\t%s\n", section_name);
4832 current_section = section_name;
4833 }
4834
4835 #ifdef USEFRAME
4836 /*
4837 * Check offset is within range for frame pointer
4838 */
4839
CheckOffset(int val)4840 int CheckOffset(int val)
4841 {
4842 if (val >= -126 && val <= 127)
4843 return 1;
4844 return 0;
4845 }
4846
4847 /*
4848 * Output offset to index register
4849 *
4850 * FRAME POINTER STUFF IS BROKEN - DO NOT USE!!!
4851 */
4852
OutIndex(int val)4853 void OutIndex(int val)
4854 {
4855 outstr("(");
4856 if (c_framepointer_is_ix)
4857 outstr("ix ");
4858 else
4859 outstr("iy ");
4860 if (val >= 0)
4861 outstr("+");
4862 outdec(val);
4863 outstr(")");
4864 }
4865
4866
4867
4868 #endif
4869
gen_push_frame(void)4870 void gen_push_frame(void)
4871 {
4872 if (c_framepointer_is_ix != -1 || (currfn->ctype->flags & (SAVEFRAME|NAKED)) == SAVEFRAME ) {
4873 if ( !IS_808x() && !IS_GBZ80() ) {
4874 ot("push\t");
4875 outstr(FRAME_REGISTER);
4876 nl();
4877 if ( c_framepointer_is_ix != -1) {
4878 ot("ld\t");
4879 outstr(FRAME_REGISTER);
4880 outstr(",0\n");
4881 ot("add\t");
4882 outstr(FRAME_REGISTER);
4883 outstr(",sp\n");
4884 }
4885 } else {
4886 ol("push\taf");
4887 }
4888 }
4889 }
4890
gen_pop_frame(void)4891 void gen_pop_frame(void)
4892 {
4893 if (c_framepointer_is_ix != -1 || (currfn->ctype->flags & (SAVEFRAME|NAKED)) == SAVEFRAME ) {
4894 if ( !IS_808x() && !IS_GBZ80() ) {
4895 ot("pop\t");
4896 outstr(FRAME_REGISTER);
4897 nl();
4898 } else {
4899 ol("pop\taf");
4900 }
4901 }
4902 }
4903
4904
gen_builtin_strcpy()4905 void gen_builtin_strcpy()
4906 {
4907 int label;
4908 // hl holds src on entry, on stack= dest
4909 ol("pop\tde");
4910 ol("push\tde");
4911 label = getlabel();
4912 if ( IS_GBZ80() ) {
4913 postlabel(label);
4914 ol("ld\ta,(hl+)");
4915 ol("ld\t(de),a");
4916 ol("inc\tde");
4917 ol("and\ta");
4918 outstr("\tjr\tnz,");
4919 printlabel(label);
4920 nl();
4921 } else {
4922 ol("xor\ta");
4923 postlabel(label);
4924 ol("cp\t(hl)");
4925 ol("ldi");
4926 outstr("\tjr\tnz,");
4927 printlabel(label);
4928 nl();
4929 }
4930 ol("pop\thl");
4931 }
4932
4933
gen_builtin_strchr(int32_t c)4934 void gen_builtin_strchr(int32_t c)
4935 {
4936 int startlabel, endlabel;
4937 if ( c == -1 ) {
4938 /* hl = c, stack = buffer */
4939 if ( IS_GBZ80() ) {
4940 ol("ld\td,h");
4941 ol("ld\te,l");
4942 } else {
4943 ol("ex\tde,hl");
4944 }
4945 ol("pop\thl");
4946 Zsp += 2;
4947 } else {
4948 /* hl = buffer */
4949 outstr("\tld\te,"); outdec(c % 256); nl();
4950 }
4951 startlabel = getlabel();
4952 endlabel = getlabel();
4953 postlabel(startlabel);
4954 ol("ld\ta,(hl)");
4955 ol("cp\te");
4956 outstr("\tjr\tz,");
4957 printlabel(endlabel); nl();
4958 ol("and\ta");
4959 ol("inc\thl");
4960 outstr("\tjr\tnz,");
4961 printlabel(startlabel); nl();
4962 ol("ld\th,a");
4963 ol("ld\tl,h");
4964 postlabel(endlabel);
4965 }
4966
gen_builtin_memset(int32_t c,int32_t s)4967 void gen_builtin_memset(int32_t c, int32_t s)
4968 {
4969 if ( c == -1 ) {
4970 /* Entry hl = c, on stack = buffer */
4971 if ( IS_GBZ80() ) {
4972 ol("ld\td,h");
4973 ol("ld\te,l");
4974 } else {
4975 ol("ex\tde,hl"); /* c */
4976 }
4977 ol("pop\thl"); /* buffer */
4978 Zsp += 2;
4979 } else {
4980 /* hl is buffer - data load happens a bit later*/
4981 }
4982 ol("push\thl");
4983
4984 /* Now decide what to do about the count */
4985 if ( s < 4 ) {
4986 int i;
4987 for ( i = 0; i < s; i++ ) {
4988 if ( i != 0 ) {
4989 ol("inc\thl");
4990 }
4991 if ( c != -1 ) {
4992 outstr("\tld\t(hl),"); outdec(c % 256); nl();
4993 } else {
4994 ol("ld\t(hl),e");
4995 }
4996 }
4997 } else if ( s <= 256 ) {
4998 int looplabel = getlabel();
4999 if ( c != -1 ) {
5000 outstr("\tld\te,"); outdec(c % 256); nl();
5001 }
5002 outstr("\tld\tb,"); outdec(s % 256); nl();
5003 postlabel(looplabel);
5004 ol("ld\t(hl),e");
5005 ol("inc\thl");
5006 outstr("\tdjnz\t"); printlabel(looplabel); nl();
5007 } else {
5008 if ( c != -1 ) {
5009 outstr("\tld\t(hl),"); outdec(c % 256); nl();
5010 } else {
5011 ol("ld\t(hl),e");
5012 }
5013 ol("ld\td,h");
5014 ol("ld\te,l");
5015 ol("inc\tde");
5016 outstr("\tld\tbc,"); outdec((s % 65536) - 1); nl();
5017 ol("ldir");
5018 }
5019 ol("pop\thl");
5020 }
5021
gen_builtin_memcpy(int32_t src,int32_t n)5022 void gen_builtin_memcpy(int32_t src, int32_t n)
5023 {
5024 if ( src == -1 ) {
5025 /* Entry hl = src, on stack = dst */
5026 ol("pop\tde"); /* dst */
5027 ol("push\tde");
5028 Zsp += 2;
5029 outstr("\tld\tbc,"); outdec(n % 65536); nl();
5030 ol("ldir");
5031 } else {
5032 /* hl is dst */
5033 ol("push\thl");
5034 ol("ex\tde,hl");
5035 outstr("\tld\thl,"); outdec(src % 65536); nl();
5036 outstr("\tld\tbc,"); outdec(n % 65536); nl();
5037 ol("ldir");
5038 }
5039 ol("pop\thl");
5040 }
5041
5042
copy_to_stack(char * label,int stack_offset,int size)5043 void copy_to_stack(char *label, int stack_offset, int size)
5044 {
5045 vconst(stack_offset);
5046 ol("add\thl,sp");
5047 ol("ex\tde,hl");
5048 outstr("\tld\thl,"); outname(label, 1); nl();
5049 outfmt("\tld\tbc,%d\n",size);
5050 ol("ldir");
5051 }
5052
copy_to_extern(const char * src,const char * dest,int size)5053 void copy_to_extern(const char *src, const char *dest, int size)
5054 {
5055 if ( size == 1 ) {
5056 outfmt("\tld\ta,(_%s)\n",src); // 6 bytes
5057 outfmt("\tld\t(_%s),a\n",dest);
5058 } else if ( size == 2 ) {
5059 outfmt("\tld\thl,(_%s)\n",src); // 6 bytes
5060 outfmt("\tld\t(_%s),hl\n",dest);
5061 } else {
5062 outfmt("\tld\thl,_%s\n",src); // 11 bytes
5063 outfmt("\tld\tde,_%s\n",dest);
5064 outfmt("\tld\tbc,%d\n",size);
5065 outfmt("\tldir\n",src);
5066 }
5067 }
5068
5069
gen_intrinsic_in(SYMBOL * sym)5070 void gen_intrinsic_in(SYMBOL *sym)
5071 {
5072 if ( c_cpu & CPU_RABBIT ) {
5073 ol("ioi");
5074 outstr("\tld\thl,("); outname(sym->name, 1); outstr(")"); nl();
5075 if ( c_cpu == CPU_R2K ) {
5076 ol("nop"); // Rabbit bug workaround
5077 }
5078 return;
5079 } else if ( IS_GBZ80() ) {
5080 outstr("\tldh\ta,("); outname(sym->name, 1); outstr(")"); nl();
5081 ol("ld\tl,a");
5082 ol("ld\th,0");
5083 return;
5084 }
5085 if (sym->type == KIND_PORT8 ) {
5086 if ( c_cpu == CPU_Z180 ) {
5087 outstr("\tin0\tl,("); outname(sym->name, 1); outstr(")"); nl();
5088 } else {
5089 outstr("\tin\ta,("); outname(sym->name, 1); outstr(")"); nl();
5090 ol("ld\tl,a");
5091 }
5092 ol("ld\th,0");
5093 } else {
5094 outstr("\tld\ta,"); outname(sym->name, 1); outstr(" / 256"); nl();
5095 outstr("\tin\ta,("); outname(sym->name, 1); outstr(" % 256)"); nl();
5096 ol("ld\tl,a");
5097 ol("ld\th,0");
5098 }
5099 }
5100
gen_intrinsic_out(SYMBOL * sym)5101 void gen_intrinsic_out(SYMBOL *sym)
5102 {
5103 if ( c_cpu & CPU_RABBIT ) {
5104 ol("ld\ta,l");
5105 ol("ioi");
5106 outstr("\tld\t("); outname(sym->name, 1); outstr("),a"); nl();
5107 if ( c_cpu == CPU_R2K ) {
5108 ol("nop"); // Rabbit bug workaround
5109 }
5110 return;
5111 } else if ( IS_GBZ80() ) {
5112 ol("ld\ta,l");
5113 outstr("\tldh\t("); outname(sym->name, 1); outstr("),a"); nl();
5114 return;
5115 }
5116 if (sym->type == KIND_PORT8 ) {
5117 if ( c_cpu == CPU_Z180 ) {
5118 outstr("\tout0\t("); outname(sym->name, 1); outstr("),l"); nl();
5119 } else {
5120 ol("ld\ta,l");
5121 outstr("\tout\t("); outname(sym->name, 1); outstr("),a"); nl();
5122 }
5123 } else {
5124 ol("ld\ta,l");
5125 outstr("\tld\tbc,"); outname(sym->name, 1); nl();
5126 ol("out\t(c),a");
5127 }
5128 }
5129
5130
zinterruptoffset(SYMBOL * sym)5131 int zinterruptoffset(SYMBOL *sym)
5132 {
5133 if ( IS_808x() || IS_GBZ80() ) {
5134 return 8;
5135 }
5136 return 12;
5137 }
5138
gen_interrupt_enter(SYMBOL * func)5139 void gen_interrupt_enter(SYMBOL *func)
5140 {
5141 // __critical __interrupt(0) -> push
5142 // __interrupt -> ei push
5143 // __critical __interrupt -> push
5144 if ( (func->ctype->flags & CRITICAL) == 0 && func->ctype->funcattrs.interrupt < 0 ) {
5145 if ( c_cpu & CPU_RABBIT ) ol("ipres");
5146 else ol("ei");
5147 }
5148
5149 ol("push\taf");
5150 ol("push\tbc");
5151 ol("push\tde");
5152 ol("push\thl");
5153 if ( !IS_808x() && !IS_GBZ80() ) {
5154 ol("push\tix");
5155 ol("push\tiy");
5156 }
5157
5158 }
gen_interrupt_leave(SYMBOL * func)5159 void gen_interrupt_leave(SYMBOL *func)
5160 {
5161 if ( !IS_808x() && !IS_GBZ80() ) {
5162 ol("pop\tiy");
5163 ol("pop\tix");
5164 }
5165 ol("pop\thl");
5166 ol("pop\tde");
5167 ol("pop\tbc");
5168 ol("pop\taf");
5169
5170 // __critical __interrupt(0) -> ei, reti
5171 // __interrupt -> reti
5172 // __critical __interrupt -> retn
5173
5174 if ( (func->ctype->flags & CRITICAL) == CRITICAL && func->ctype->funcattrs.interrupt < 0 ) {
5175 if ( c_cpu & CPU_RABBIT ) ol("ret");
5176 else ol("retn");
5177 } else if ( (func->ctype->flags & CRITICAL) == 0 && func->ctype->funcattrs.interrupt < 0 ) {
5178 ol("reti");
5179 } else {
5180 if ( c_cpu & CPU_RABBIT ) ol("ipres");
5181 else ol("ei");
5182 ol("reti");
5183 }
5184 nl();
5185 nl();
5186 }
5187
5188
5189
gen_critical_enter(void)5190 void gen_critical_enter(void)
5191 {
5192 if ( c_cpu & CPU_RABBIT ) {
5193 ol("ipset\t3");
5194 } else {
5195 callrts("l_push_di");
5196 Zsp -= 2;
5197 }
5198 }
5199
gen_critical_leave(void)5200 void gen_critical_leave(void)
5201 {
5202 if ( c_cpu & CPU_RABBIT ) {
5203 ol("ipres");
5204 } else {
5205 callrts("l_pop_ei");
5206 Zsp += 2;
5207 }
5208 }
5209
zcriticaloffset(void)5210 int zcriticaloffset(void)
5211 {
5212 if ( c_cpu & CPU_RABBIT ) {
5213 return 0;
5214 }
5215 return 2;
5216 }
5217
5218
5219
zconvert_from_double(Kind from,Kind to,unsigned char isunsigned)5220 void zconvert_from_double(Kind from, Kind to, unsigned char isunsigned)
5221 {
5222 if ( to == KIND_LONGLONG ) {
5223 if ( isunsigned ) dcallrts("f2ullong",from);
5224 else dcallrts("f2sllong",from);
5225 } else if ( to == KIND_LONG || to == KIND_CPTR ) {
5226 if ( isunsigned ) dcallrts("f2ulong",from);
5227 else dcallrts("f2slong",from);
5228 } else if ( isunsigned ) {
5229 dcallrts("f2uint",from);
5230 } else {
5231 dcallrts("f2sint",from);
5232 }
5233 }
5234
gen_load_constant_as_float(double val,Kind to,unsigned char isunsigned)5235 void gen_load_constant_as_float(double val, Kind to, unsigned char isunsigned)
5236 {
5237 unsigned char fa[8] = {0};
5238 LVALUE lval = {0};
5239
5240 if ( to == KIND_FLOAT16 ) {
5241 lval.const_val = val;
5242 lval.val_type = KIND_FLOAT16;
5243 load_double_into_fa(&lval);
5244 } else if ( c_fp_size == 4 ) {
5245 dofloat(c_maths_mode,val, fa);
5246 vconst((fa[1] << 8) | fa[0]);
5247 const2((fa[3] << 8) | fa[2]);
5248 } else {
5249 // Long doubles, for integer values we can load an int constant and convert, this
5250 // is shorter but slower than loading the floating constant directly
5251 isunsigned = val >= 0;
5252 if ( val >= INT16_MIN && val <= UINT16_MAX &&
5253 (c_speed_optimisation & OPT_DOUBLE_CONST) == 0 && fmod(val,1) == 0.0 ) {
5254 vconst(val);
5255 zconvert_to_double(KIND_INT,to, isunsigned);
5256 } else if ( val >= INT32_MIN && val <= UINT32_MAX &&
5257 (c_speed_optimisation & OPT_DOUBLE_CONST) == 0 && fmod(val,1) == 0.0) {
5258 vlongconst(val);
5259 zconvert_to_double(KIND_LONG,to, isunsigned);
5260 } else {
5261 lval.val_type = to;
5262 lval.const_val = val;
5263 load_double_into_fa(&lval);
5264 }
5265 }
5266 }
5267
5268 // Convert the value that's on the stack to a double and restore stack to appropriate state
5269 // We have a float in the primary register
zconvert_stacked_to_double(Kind stacked_kind,Kind float_kind,unsigned char isunsigned,int operator_is_commutative)5270 void zconvert_stacked_to_double(Kind stacked_kind, Kind float_kind, unsigned char isunsigned, int operator_is_commutative)
5271 {
5272 if ( float_kind == KIND_FLOAT16) {
5273 if ( stacked_kind == KIND_LONG ) {
5274 pop("de"); // LSW
5275 ol("ex\t(sp),hl"); // hl = MSW, stack = float
5276 ol("ex\tde,hl");
5277 zconvert_to_double(stacked_kind, float_kind, isunsigned);
5278 if (!operator_is_commutative) ol("ex\t(sp),hl");
5279 } else if ( stacked_kind == KIND_LONGLONG) {
5280 /* Pop the longlong into the accumulator */
5281 ol("exx");
5282 callrts("l_i64_pop"); // Preserves
5283 ol("exx");
5284 Zsp += 8;
5285 /* Push the float */
5286 push("hl");
5287 /* And convert */
5288 zconvert_to_double(stacked_kind, float_kind, isunsigned);
5289 if (!operator_is_commutative) ol("ex\t(sp),hl");
5290 } else {
5291 // 2 bytes on stack
5292 ol("ex\t(sp),hl"); //
5293 zconvert_to_double(stacked_kind, float_kind, isunsigned);
5294 if (!operator_is_commutative) ol("ex\t(sp),hl");
5295 }
5296 } else if ( stacked_kind == KIND_LONGLONG ) {
5297 /* Pop the longlong into the accumulator
5298 * If we're using 4 byte longs, then they are held in dehl, so we need to preserve the register
5299 * If bigger, then they are held in FA or in alt registers, so we can trash the main set
5300 */
5301 if ( c_fp_size < 6 ) ol("exx");
5302 callrts("l_i64_pop"); // Preserves
5303 if ( c_fp_size < 6 ) ol("exx");
5304 Zsp += 8;
5305 /* Push the float */
5306 gen_push_float(float_kind);
5307 /* And convert the long */
5308 zconvert_to_double(stacked_kind, float_kind, isunsigned);
5309 if (!operator_is_commutative) gen_swap_float(float_kind);
5310 } else {
5311 dpush_under(stacked_kind);
5312 pop("hl");
5313 if (stacked_kind == KIND_LONG)
5314 zpop();
5315 zconvert_to_double(stacked_kind, float_kind, isunsigned);
5316 if (!operator_is_commutative) gen_swap_float(float_kind);
5317 }
5318 }
5319
5320
zconvert_to_double(Kind from,Kind to,unsigned char isunsigned)5321 void zconvert_to_double(Kind from, Kind to, unsigned char isunsigned)
5322 {
5323 if ( from == to ) {
5324 return;
5325 } else if ( from == KIND_LONGLONG ) {
5326 if ( isunsigned ) dcallrts("ullong2f",to);
5327 else dcallrts("sllong2f",to);
5328 return;
5329 } else if ( from == KIND_LONG || from == KIND_CPTR ) {
5330 if ( isunsigned ) dcallrts("ulong2f",to);
5331 else dcallrts("slong2f",to);
5332 return;
5333 } else if ( from == KIND_CHAR ) {
5334 if ( isunsigned ) dcallrts("uchar2f",to);
5335 else dcallrts("schar2f",to);
5336 return;
5337 } else if ( from == KIND_CARRY ) {
5338 gen_conv_carry2int();
5339 isunsigned = 1;
5340 } else if ( from == KIND_FLOAT16 ) {
5341 dcallrts("f16tof",to);
5342 return;
5343 } else if ( from == KIND_DOUBLE ) {
5344 dcallrts("ftof16", from);
5345 return;
5346 }
5347 if ( isunsigned ) dcallrts("uint2f",to);
5348 else dcallrts("sint2f",to);
5349 }
5350
zconvert_to_llong(unsigned char tounsigned,Kind from,unsigned char fromunsigned)5351 void zconvert_to_llong(unsigned char tounsigned, Kind from, unsigned char fromunsigned) {
5352 if (tounsigned == NO && fromunsigned == NO) {
5353 if (from == KIND_LONG) callrts("l_i64_slong2i64");
5354 else callrts("l_i64_sint2i64");
5355 } else {
5356 if (from == KIND_LONG) callrts("l_i64_ulong2i64");
5357 else callrts("l_i64_uint2i64");
5358 }
5359 }
5360
zwiden_stack_to_llong(LVALUE * lval)5361 void zwiden_stack_to_llong(LVALUE *lval)
5362 {
5363 // We have a value in _i64_acc already
5364 pop("hl");
5365 push("hl");
5366 if ( lval->ltype->isunsigned ) {
5367 vconst(0);
5368 } else {
5369 ol("ld\ta,h");
5370 ol("rlca");
5371 ol("sbc\ta");
5372 ol("ld\tl,a");
5373 ol("ld\th,a");
5374 }
5375 push("hl");
5376 push("hl");
5377 if ( lval->val_type != KIND_LONG ) {
5378 push("hl");
5379 }
5380 }
5381
zconvert_to_long(unsigned char tounsigned,Kind from,unsigned char fromunsigned)5382 void zconvert_to_long(unsigned char tounsigned, Kind from, unsigned char fromunsigned) {
5383 if (tounsigned == NO && fromunsigned == NO) {
5384 gen_conv_sint2long();
5385 } else {
5386 gen_conv_uint2long();
5387 }
5388 }
5389
zwiden_stack_to_long(LVALUE * lval)5390 void zwiden_stack_to_long(LVALUE *lval)
5391 {
5392 if ( IS_808x() || IS_GBZ80() ) {
5393 int label = getlabel();
5394 // We have a value in dehl that we must preserve
5395 ol("ld\tc,l");
5396 ol("ld\tb,h");
5397 ol("ld\thl,0");
5398 ol("ex\t(sp),hl"); // Emulated on GBZ80 unfortunately
5399 ol("ld\ta,h");
5400 ol("rlca");
5401 opjumpr("nc,",label);
5402 ol("ex\t(sp),hl"); // Emulated on GBZ80 unfortunately
5403 ol("dec\thl");
5404 ol("ex\t(sp),hl"); // Emulated on GBZ80 unfortunately
5405 postlabel(label);
5406 push("hl");
5407 ol("ld\tl,c");
5408 ol("ld\th,b");
5409 } else {
5410 ol("exx"); /* Preserve other operator */
5411 pop("hl");
5412 force(KIND_LONG, lval->val_type, lval->ltype->isunsigned, lval->ltype->isunsigned, 0);
5413 lpush(); /* Put the new expansion on stk*/
5414 ol("exx"); /* Get it back again */
5415 }
5416 }
5417
gen_switch_preamble(Kind kind)5418 void gen_switch_preamble(Kind kind)
5419 {
5420 if ( kind == KIND_CHAR ) {
5421 ol("ld\ta,l");
5422 } else if (kind == KIND_LONGLONG) {
5423 callrts("l_i64_case");
5424 } else if (kind == KIND_LONG || kind == KIND_CPTR) {
5425 callrts("l_long_case");
5426 } else {
5427 callrts("l_case");
5428 }
5429 }
5430
gen_switch_case(Kind kind,int64_t value,int label)5431 void gen_switch_case(Kind kind, int64_t value, int label)
5432 {
5433 if ( kind == KIND_CHAR ) {
5434 if ( value == 0 ) {
5435 ol("and\ta");
5436 } else {
5437 ot("cp\t+(");
5438 outdec(value);
5439 outstr("% 256)\n");
5440 }
5441 opjump("z,", label);
5442 } else {
5443 defword();
5444 printlabel(label); /* case label */
5445 nl();
5446 if ( kind == KIND_LONGLONG ) {
5447 uint64_t l;
5448 l = value & 0xffffffff;
5449 outfmt("\tdefb\t$%02x,$%02x,$%02x,$%02x\n", (l % 65536 ) % 256, (l % 65536 ) / 256, (l / 65536) % 256, (l / 65536) / 256 );
5450 l = (value >> 32) & 0xffffffff;
5451 outfmt("\tdefb\t$%02x,$%02x,$%02x,$%02x\n", (l % 65536 ) % 256, (l % 65536 ) / 256, (l / 65536) % 256, (l / 65536) / 256 );
5452 } else {
5453 if ( kind == KIND_LONG || kind == KIND_CPTR) {
5454 deflong();
5455 } else {
5456 defword();
5457 }
5458 outdec(value); /* case value */
5459 nl();
5460 }
5461 }
5462 }
5463
gen_switch_postamble(Kind kind)5464 void gen_switch_postamble(Kind kind)
5465 {
5466 // Table terminator
5467
5468 if ( kind != KIND_CHAR ) {
5469 defword();
5470 outdec(0);
5471 nl();
5472 }
5473 }
5474
5475 /*
5476 * Local Variables:
5477 * indent-tabs-mode:nil
5478 * require-final-newline:t
5479 * c-basic-offset: 4
5480 * eval: (c-set-offset 'case-label 0)
5481 * eval: (c-set-offset 'substatement-open 0)
5482 * eval: (c-set-offset 'access-label 0)
5483 * eval: (c-set-offset 'class-open 4)
5484 * eval: (c-set-offset 'class-close 4)
5485 * End:
5486 */
5487