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