--- hatari/src/uae-cpu/gencpu.c 2019/04/01 07:09:16 1.1.1.1 +++ hatari/src/uae-cpu/gencpu.c 2019/04/09 08:53:25 1.1.1.16 @@ -1,5 +1,5 @@ /* - * UAE - The Un*x Amiga Emulator + * UAE - The Un*x Amiga Emulator - CPU core * * MC68000 emulation generator * @@ -16,15 +16,64 @@ * The source for the insn timings is Markt & Technik's Amiga Magazin 8/1992. * * Copyright 1995, 1996, 1997, 1998, 1999, 2000 Bernd Schmidt + * + * Adaptation to Hatari and better cpu timings by Thomas Huth + * + * This file is distributed under the GNU General Public License, version 2 + * or at your option any later version. Read the file gpl.txt for details. */ + +/* 2007/03/xx [NP] Use add_cycles.pl to set 'CurrentInstrCycles' in each opcode. */ +/* 2007/04/09 [NP] Correct CLR : on 68000, CLR reads the memory before clearing it (but we should */ +/* not add cycles for reading). This means CLR can give 2 wait states (one for */ +/* read and one for right) (clr.b $fa1b.w in Decade's Demo Main Menu). */ +/* 2007/04/14 [NP] - Although dest -(an) normally takes 2 cycles, this is not the case for move : */ +/* move dest (an), (an)+ and -(an) all take the same time (curi->dmode == Apdi) */ +/* (Syntax Terror Demo Reset). */ +/* - Scc takes 6 cycles instead of 4 if the result is true (Ventura Demo Loader). */ +/* - Store the family of the current opcode into OpcodeFamily : used to check */ +/* instruction pairing on ST into m68000.c */ +/* 2007/04/17 [NP] Add support for cycle accurate MULU (No Cooper Greeting Screen). */ +/* 2007/04/24 [NP] BCLR #n,Dx takes 12 cycles instead of 14 if n<16 (ULM Demo Menu). */ +/* 2007/04/25 [NP] On ST, d8(An,Xn) and d8(PC,Xn) take 2 cycles more than the official 68000's */ +/* table (ULM Demo Menu). */ +/* 2007/11/12 [NP] Add refill_prefetch for i_ADD to fix Transbeauce 2 demo self modified code. */ +/* Ugly hack, we need better prefetch emulation (switch to winuae gencpu.c) */ +/* 2007/11/25 [NP] In i_DBcc, in case of address error, last_addr_for_exception_3 should be */ +/* pc+4, not pc+2 (Transbeauce 2 demo) (e.g. 'dbf d0,#$fff5'). */ +/* This means the value pushed on the frame stack should be the address of the */ +/* instruction following the one generating the address error. */ +/* FIXME : this should be the case for i_BSR and i_BCC too (need to check on */ +/* a real 68000). */ +/* 2007/11/28 [NP] Backport DIVS/DIVU cycles exact routines from WinUAE (original work by Jorge */ +/* Cwik, pasti@fxatari.com). */ +/* 2007/12/08 [NP] In case of CHK/CHK2 exception, PC stored on the stack wasn't pointing to the */ +/* next instruction but to the current CHK/CHK2 instruction (Transbeauce 2 demo). */ +/* We need to call 'sync_m68k_pc' before calling 'Exception'. */ +/* 2007/12/09 [NP] CHK.L (e.g. $4700) doesn't exist on 68000 and should be considered as an illegal*/ +/* instruction (Transbeauce 2 demo) -> change in table68k. */ +/* 2008/01/24 [NP] BCLR Dy,Dx takes 8 cycles instead of 10 if Dy<16 (Fullshade in Anomaly Demos). */ +/* 2008/01/26 [NP] On ST, d8(An,Xn) takes 2 cycles more when used with ADDA/SUBA (ULM Demo Menu) */ +/* but not when used with MOVE (e.g. 'move.l 0(a5,d1),(a4)' takes 26 cycles and so */ +/* can pair with a lsr) (Anomaly Demo Intro). */ +/* 2008/04/26 [NP] Handle sz_byte for Areg in genamode, as 'move.b a1,(a0)' ($1089) is possible */ +/* on ST (fix Blood Money on Superior 65) */ +/* 2010/04/05 [NP] On ST, d8(An,Xn) takes 2 cycles more (which can generate pairing). */ +/* Use BusCyclePenalty to properly handle the 2/4 cycles added in that case when */ +/* addressing mode is Ad8r or PC8r (ULM Demo Menu, Anomaly Demo Intro, DHS */ +/* Sommarhack 2010) (see m68000.h) */ +/* 2012/01/29 [NP] Add refill_prefetch for i_EOR to fix Operation Clean Streets self modified code.*/ +/* Ugly hack, we need better prefetch emulation (switch to winuae gencpu.c) */ +/* 2012/05/05 [NP] In i_JMP, in case of address error, last_addr_for_exception_3 should not always */ +/* be pc+6, (Sherman Cracktro in No Extra V2 compilation) (e.g. 'jmp (a2)' : pc+2) */ + + +const char GenCpu_fileid[] = "Hatari gencpu.c : " __DATE__ " " __TIME__; + #include +#include -/* -#include "sysconfig.h" -#include "config.h" -#include "options.h" -*/ #include "sysdeps.h" #include "readcpu.h" @@ -37,21 +86,20 @@ static int using_prefetch; static int using_exception_3; static int cpu_level; +char exactCpuCycles[256]; /* Space to store return string for exact cpu cycles */ + +long nCurInstrCycPos; /* Stores where we have to patch in the current cycles value */ + /* For the current opcode, the next lower level that will have different code. * Initialized to -1 for each opcode. If it remains unchanged, indicates we * are done with that opcode. */ static int next_cpu_level; - -void write_log (const char *s, ...) -{ - fprintf (stderr, "%s", s); -} - static int *opcode_map; static int *opcode_next_clev; static int *opcode_last_postfix; static unsigned long *counts; + static void read_counts (void) { FILE *file; @@ -62,7 +110,9 @@ static void read_counts (void) file = fopen ("frequent.68k", "r"); if (file) { - fscanf (file, "Total: %lu\n", &total); + if (fscanf (file, "Total: %lu\n", &total) == EOF) { + perror("read_counts"); + } while (fscanf (file, "%lx: %lu %s\n", &opcode, &count, name) == 3) { opcode_next_clev[nr] = 4; opcode_last_postfix[nr] = -1; @@ -219,8 +269,10 @@ static void sync_m68k_pc (void) } /* getv == 1: fetch data; getv != 0: check for odd address. If movem != 0, - * the calling routine handles Apdi and Aipi modes. */ -static void genamode (amodes mode, char *reg, wordsizes size, char *name, int getv, int movem) + * the calling routine handles Apdi and Aipi modes. + * gb-- movem == 2 means the same thing but for a MOVE16 instruction */ +static void genamode (amodes mode, const char *reg, wordsizes size, + const char *name, int getv, int movem) { start_brace (); switch (mode) { @@ -230,20 +282,10 @@ static void genamode (amodes mode, char if (getv == 1) switch (size) { case sz_byte: -#if defined(AMIGA) && !defined(WARPUP) - /* sam: I don't know why gcc.2.7.2.1 produces a code worse */ - /* if it is not done like that: */ - printf ("\tuae_s8 %s = ((uae_u8*)&m68k_dreg(regs, %s))[3];\n", name, reg); -#else printf ("\tuae_s8 %s = m68k_dreg(regs, %s);\n", name, reg); -#endif break; case sz_word: -#if defined(AMIGA) && !defined(WARPUP) - printf ("\tuae_s16 %s = ((uae_s16*)&m68k_dreg(regs, %s))[1];\n", name, reg); -#else printf ("\tuae_s16 %s = m68k_dreg(regs, %s);\n", name, reg); -#endif break; case sz_long: printf ("\tuae_s32 %s = m68k_dreg(regs, %s);\n", name, reg); @@ -257,6 +299,9 @@ static void genamode (amodes mode, char abort (); if (getv == 1) switch (size) { + case sz_byte: // [NP] Areg with .b is possible in MOVE source */ + printf ("\tuae_s8 %s = m68k_areg(regs, %s);\n", name, reg); + break; case sz_word: printf ("\tuae_s16 %s = m68k_areg(regs, %s);\n", name, reg); break; @@ -305,8 +350,10 @@ static void genamode (amodes mode, char /* This would ordinarily be done in gen_nextiword, which we bypass. */ insn_n_cycles += 4; printf ("\tuaecptr %sa = get_disp_ea_020(m68k_areg(regs, %s), next_iword());\n", name, reg); - } else + } else { printf ("\tuaecptr %sa = get_disp_ea_000(m68k_areg(regs, %s), %s);\n", name, reg, gen_nextiword ()); + } + printf ("\tBusCyclePenalty += 2;\n"); break; case PC16: @@ -328,6 +375,7 @@ static void genamode (amodes mode, char printf ("\tuaecptr tmppc = m68k_getpc() + %d;\n", m68k_pc_offset); printf ("\tuaecptr %sa = get_disp_ea_000(tmppc, %s);\n", name, gen_nextiword ()); } + printf ("\tBusCyclePenalty += 2;\n"); break; case absw: @@ -385,7 +433,7 @@ static void genamode (amodes mode, char printf ("\t\tlast_fault_for_exception_3 = %sa;\n", name); printf ("\t\tlast_op_for_exception_3 = opcode;\n"); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + %d;\n", m68k_pc_offset); - printf ("\t\tException(3, 0);\n"); + printf ("\t\tException(3, 0, M68000_EXC_SRC_CPU);\n"); printf ("\t\tgoto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; @@ -435,7 +483,8 @@ static void genamode (amodes mode, char } } -static void genastore (char *from, amodes mode, char *reg, wordsizes size, char *to) +static void genastore (const char *from, amodes mode, const char *reg, + wordsizes size, const char *to) { switch (mode) { case Dreg: @@ -510,12 +559,14 @@ static void genastore (char *from, amode } } + static void genmovemel (uae_u16 opcode) { char getcode[100]; - int size = table68k[opcode].size == sz_long ? 4 : 2; + int bMovemLong = (table68k[opcode].size == sz_long); + int size = bMovemLong ? 4 : 2; - if (table68k[opcode].size == sz_long) { + if (bMovemLong) { strcpy (getcode, "get_long(srca)"); } else { strcpy (getcode, "(uae_s32)(uae_s16)get_word(srca)"); @@ -523,49 +574,86 @@ static void genmovemel (uae_u16 opcode) printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); printf ("\tunsigned int dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); + printf ("\tretcycles = 0;\n"); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); start_brace (); - printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s; srca += %d; dmask = movem_next[dmask]; }\n", - getcode, size); - printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s; srca += %d; amask = movem_next[amask]; }\n", - getcode, size); + printf ("\twhile (dmask) { m68k_dreg(regs, movem_index1[dmask]) = %s;" + " srca += %d; dmask = movem_next[dmask]; retcycles+=%d; }\n", + getcode, size, (bMovemLong ? 8 : 4)); + printf ("\twhile (amask) { m68k_areg(regs, movem_index1[amask]) = %s;" + " srca += %d; amask = movem_next[amask]; retcycles+=%d; }\n", + getcode, size, (bMovemLong ? 8 : 4)); if (table68k[opcode].dmode == Aipi) printf ("\tm68k_areg(regs, dstreg) = srca;\n"); + + /* Better cycles - experimental! (Thothy) */ + switch(table68k[opcode].dmode) + { + case Aind: insn_n_cycles=12; break; + case Aipi: insn_n_cycles=12; break; + case Ad16: insn_n_cycles=16; break; + case Ad8r: insn_n_cycles=18; break; + case absw: insn_n_cycles=16; break; + case absl: insn_n_cycles=20; break; + case PC16: insn_n_cycles=16; break; + case PC8r: insn_n_cycles=18; break; + } + sprintf(exactCpuCycles," return (%i+retcycles);", insn_n_cycles); } static void genmovemle (uae_u16 opcode) { char putcode[100]; - int size = table68k[opcode].size == sz_long ? 4 : 2; - if (table68k[opcode].size == sz_long) { + int bMovemLong = (table68k[opcode].size == sz_long); + int size = bMovemLong ? 4 : 2; + + if (bMovemLong) { strcpy (putcode, "put_long(srca,"); } else { strcpy (putcode, "put_word(srca,"); } printf ("\tuae_u16 mask = %s;\n", gen_nextiword ()); + printf ("\tretcycles = 0;\n"); genamode (table68k[opcode].dmode, "dstreg", table68k[opcode].size, "src", 2, 1); if (using_prefetch) sync_m68k_pc (); start_brace (); if (table68k[opcode].dmode == Apdi) { - printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n"); - printf ("\twhile (amask) { srca -= %d; %s m68k_areg(regs, movem_index2[amask])); amask = movem_next[amask]; }\n", - size, putcode); - printf ("\twhile (dmask) { srca -= %d; %s m68k_dreg(regs, movem_index2[dmask])); dmask = movem_next[dmask]; }\n", - size, putcode); - printf ("\tm68k_areg(regs, dstreg) = srca;\n"); + printf ("\tuae_u16 amask = mask & 0xff, dmask = (mask >> 8) & 0xff;\n"); + printf ("\twhile (amask) { srca -= %d; %s m68k_areg(regs, movem_index2[amask]));" + " amask = movem_next[amask]; retcycles+=%d; }\n", + size, putcode, (bMovemLong ? 8 : 4)); + printf ("\twhile (dmask) { srca -= %d; %s m68k_dreg(regs, movem_index2[dmask]));" + " dmask = movem_next[dmask]; retcycles+=%d; }\n", + size, putcode, (bMovemLong ? 8 : 4)); + printf ("\tm68k_areg(regs, dstreg) = srca;\n"); } else { - printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); - printf ("\twhile (dmask) { %s m68k_dreg(regs, movem_index1[dmask])); srca += %d; dmask = movem_next[dmask]; }\n", - putcode, size); - printf ("\twhile (amask) { %s m68k_areg(regs, movem_index1[amask])); srca += %d; amask = movem_next[amask]; }\n", - putcode, size); + printf ("\tuae_u16 dmask = mask & 0xff, amask = (mask >> 8) & 0xff;\n"); + printf ("\twhile (dmask) { %s m68k_dreg(regs, movem_index1[dmask])); srca += %d;" + " dmask = movem_next[dmask]; retcycles+=%d; }\n", + putcode, size, (bMovemLong ? 8 : 4)); + printf ("\twhile (amask) { %s m68k_areg(regs, movem_index1[amask])); srca += %d;" + " amask = movem_next[amask]; retcycles+=%d; }\n", + putcode, size, (bMovemLong ? 8 : 4)); + } + + /* Better cycles - experimental! (Thothy) */ + switch(table68k[opcode].dmode) + { + case Aind: insn_n_cycles=8; break; + case Apdi: insn_n_cycles=8; break; + case Ad16: insn_n_cycles=12; break; + case Ad8r: insn_n_cycles=14; break; + case absw: insn_n_cycles=12; break; + case absl: insn_n_cycles=16; break; } + sprintf(exactCpuCycles," return (%i+retcycles);", insn_n_cycles); } + static void duplicate_carry (void) { printf ("\tCOPY_CARRY;\n"); @@ -578,7 +666,8 @@ typedef enum } flagtypes; -static void genflags_normal (flagtypes type, wordsizes size, char *value, char *src, char *dst) +static void genflags_normal (flagtypes type, wordsizes size, const char *value, + const char *src, const char *dst) { char vstr[100], sstr[100], dstr[100]; char usstr[100], udstr[100]; @@ -719,7 +808,8 @@ static void genflags_normal (flagtypes t } } -static void genflags (flagtypes type, wordsizes size, char *value, char *src, char *dst) +static void genflags (flagtypes type, wordsizes size, const char *value, + const char *src, const char *dst) { /* Temporarily deleted 68k/ARM flag optimizations. I'd prefer to have them in the appropriate m68k.h files and use just one copy of this @@ -830,16 +920,26 @@ static int source_is_imm1_8 (struct inst return i->stype == 3; } + + static void gen_opcode (unsigned long int opcode) { +#if 0 + char *amodenames[] = { "Dreg", "Areg", "Aind", "Aipi", "Apdi", "Ad16", "Ad8r", + "absw", "absl", "PC16", "PC8r", "imm", "imm0", "imm1", "imm2", "immi", "am_unknown", "am_illg"}; +#endif + struct instr *curi = table68k + opcode; insn_n_cycles = 4; + /* Store the family of the instruction (used to check for pairing on ST) + * and leave some space for patching in the current cycles later */ + printf ("\tOpcodeFamily = %d; CurrentInstrCycles = \n", curi->mnemo); + nCurInstrCycPos = ftell(stdout) - 5; + start_brace (); -#if 0 - printf ("uae_u8 *m68k_pc = regs.pc_p;\n"); -#endif m68k_pc_offset = 2; + switch (curi->plev) { case 0: /* not privileged */ break; @@ -851,53 +951,77 @@ static void gen_opcode (unsigned long in /* fall through */ case 2: /* priviledged */ - printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr); + printf ("if (!regs.s) { Exception(8,0,M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); need_endlabel = 1; start_brace (); break; case 3: /* privileged if size == word */ if (curi->size == sz_byte) break; - printf ("if (!regs.s) { Exception(8,0); goto %s; }\n", endlabelstr); + printf ("if (!regs.s) { Exception(8,0,M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); need_endlabel = 1; start_brace (); break; } + + /* Build the opcodes: */ switch (curi->mnemo) { case i_OR: case i_AND: case i_EOR: - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); - printf ("\tsrc %c= dst;\n", curi->mnemo == i_OR ? '|' : curi->mnemo == i_AND ? '&' : '^'); - genflags (flag_logical, curi->size, "src", "", ""); - genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); - break; + genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); + printf ("\tsrc %c= dst;\n", curi->mnemo == i_OR ? '|' : curi->mnemo == i_AND ? '&' : '^'); + printf("\trefill_prefetch (m68k_getpc(), 2);\n"); // FIXME [NP] For Operation Clean Streets - Automation 168, need better prefetch emulation + genflags (flag_logical, curi->size, "src", "", ""); + genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->size==sz_long && curi->dmode==Dreg) + { + insn_n_cycles += 2; + if(curi->smode==Dreg || curi->smode==Areg || (curi->smode>=imm && curi->smode<=immi)) + insn_n_cycles += 2; + } +#if 0 + /* Output the CPU cycles: */ + fprintf(stderr,"MOVE, size %i: ",curi->size); + fprintf(stderr," %s ->",amodenames[curi->smode]); + fprintf(stderr," %s ",amodenames[curi->dmode]); + fprintf(stderr," Cycles: %i\n",insn_n_cycles); +#endif + break; case i_ORSR: case i_EORSR: - printf ("\tMakeSR();\n"); - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - if (curi->size == sz_byte) { - printf ("\tsrc &= 0xFF;\n"); - } - printf ("\tregs.sr %c= src;\n", curi->mnemo == i_EORSR ? '^' : '|'); - printf ("\tMakeFromSR();\n"); - break; + printf ("\tMakeSR();\n"); + genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + if (curi->size == sz_byte) { + printf ("\tsrc &= 0xFF;\n"); + } + printf ("\tregs.sr %c= src;\n", curi->mnemo == i_EORSR ? '^' : '|'); + printf ("\tMakeFromSR();\n"); + insn_n_cycles = 20; + break; case i_ANDSR: - printf ("\tMakeSR();\n"); - genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); - if (curi->size == sz_byte) { - printf ("\tsrc |= 0xFF00;\n"); - } - printf ("\tregs.sr &= src;\n"); - printf ("\tMakeFromSR();\n"); - break; + printf ("\tMakeSR();\n"); + genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); + if (curi->size == sz_byte) { + printf ("\tsrc |= 0xFF00;\n"); + } + printf ("\tregs.sr &= src;\n"); + printf ("\tMakeFromSR();\n"); + insn_n_cycles = 20; + break; case i_SUB: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_sub, curi->size, "newv", "src", "dst"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->size==sz_long && curi->dmode==Dreg) + { + insn_n_cycles += 2; + if(curi->smode==Dreg || curi->smode==Areg || (curi->smode>=imm && curi->smode<=immi)) + insn_n_cycles += 2; + } break; case i_SUBA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -905,6 +1029,10 @@ static void gen_opcode (unsigned long in start_brace (); printf ("\tuae_u32 newv = dst - src;\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + if(curi->size==sz_long && curi->smode!=Dreg && curi->smode!=Areg && !(curi->smode>=imm && curi->smode<=immi)) + insn_n_cycles += 2; + else + insn_n_cycles += 4; break; case i_SUBX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -914,32 +1042,48 @@ static void gen_opcode (unsigned long in genflags (flag_subx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->smode==Dreg && curi->size==sz_long) + insn_n_cycles=8; + if(curi->smode==Apdi) + { + if(curi->size==sz_long) + insn_n_cycles=30; + else + insn_n_cycles=18; + } break; case i_SBCD: - /* Let's hope this works... */ genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); printf ("\tuae_u16 newv_lo = (dst & 0xF) - (src & 0xF) - (GET_XFLG ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (dst & 0xF0) - (src & 0xF0);\n"); - printf ("\tuae_u16 newv;\n"); - printf ("\tint cflg;\n"); - printf ("\tif (newv_lo > 9) { newv_lo-=6; newv_hi-=0x10; }\n"); - printf ("\tnewv = newv_hi + (newv_lo & 0xF);"); - printf ("\tcflg = (newv_hi & 0x1F0) > 0x90;\n"); - printf ("\tSET_CFLG (cflg);\n"); + printf ("\tuae_u16 newv, tmp_newv;\n"); + printf ("\tint bcd = 0;\n"); + printf ("\tnewv = tmp_newv = newv_hi + newv_lo;\n"); + printf ("\tif (newv_lo & 0xF0) { newv -= 6; bcd = 6; };\n"); + printf ("\tif ((((dst & 0xFF) - (src & 0xFF) - (GET_XFLG ? 1 : 0)) & 0x100) > 0xFF) { newv -= 0x60; }\n"); + printf ("\tSET_CFLG ((((dst & 0xFF) - (src & 0xFF) - bcd - (GET_XFLG ? 1 : 0)) & 0x300) > 0xFF);\n"); duplicate_carry (); - printf ("\tif (cflg) newv -= 0x60;\n"); genflags (flag_zn, curi->size, "newv", "", ""); - genflags (flag_sv, curi->size, "newv", "src", "dst"); + printf ("\tSET_VFLG ((tmp_newv & 0x80) != 0 && (newv & 0x80) == 0);\n"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->smode==Dreg) insn_n_cycles=6; + if(curi->smode==Apdi) insn_n_cycles=18; break; case i_ADD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); + printf("\trefill_prefetch (m68k_getpc(), 2);\n"); // FIXME [NP] For Transbeauce 2 demo, need better prefetch emulation genflags (flag_add, curi->size, "newv", "src", "dst"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->size==sz_long && curi->dmode==Dreg) + { + insn_n_cycles += 2; + if(curi->smode==Dreg || curi->smode==Areg || (curi->smode>=imm && curi->smode<=immi)) + insn_n_cycles += 2; + } break; case i_ADDA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -947,6 +1091,10 @@ static void gen_opcode (unsigned long in start_brace (); printf ("\tuae_u32 newv = dst + src;\n"); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); + if(curi->size==sz_long && curi->smode!=Dreg && curi->smode!=Areg && !(curi->smode>=imm && curi->smode<=immi)) + insn_n_cycles += 2; + else + insn_n_cycles += 4; break; case i_ADDX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -956,6 +1104,15 @@ static void gen_opcode (unsigned long in genflags (flag_addx, curi->size, "newv", "src", "dst"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->smode==Dreg && curi->size==sz_long) + insn_n_cycles=8; + if(curi->smode==Apdi) + { + if(curi->size==sz_long) + insn_n_cycles=30; + else + insn_n_cycles=18; + } break; case i_ABCD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -963,23 +1120,26 @@ static void gen_opcode (unsigned long in start_brace (); printf ("\tuae_u16 newv_lo = (src & 0xF) + (dst & 0xF) + (GET_XFLG ? 1 : 0);\n"); printf ("\tuae_u16 newv_hi = (src & 0xF0) + (dst & 0xF0);\n"); - printf ("\tuae_u16 newv;\n"); + printf ("\tuae_u16 newv, tmp_newv;\n"); printf ("\tint cflg;\n"); - printf ("\tif (newv_lo > 9) { newv_lo +=6; }\n"); - printf ("\tnewv = newv_hi + newv_lo;"); - printf ("\tcflg = (newv & 0x1F0) > 0x90;\n"); + printf ("\tnewv = tmp_newv = newv_hi + newv_lo;"); + printf ("\tif (newv_lo > 9) { newv += 6; }\n"); + printf ("\tcflg = (newv & 0x3F0) > 0x90;\n"); + printf ("\tif (cflg) newv += 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry (); - printf ("\tif (cflg) newv += 0x60;\n"); genflags (flag_zn, curi->size, "newv", "", ""); - genflags (flag_sv, curi->size, "newv", "src", "dst"); + printf ("\tSET_VFLG ((tmp_newv & 0x80) == 0 && (newv & 0x80) != 0);\n"); genastore ("newv", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->smode==Dreg) insn_n_cycles=6; + if(curi->smode==Apdi) insn_n_cycles=18; break; case i_NEG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); start_brace (); genflags (flag_sub, curi->size, "dst", "src", "0"); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); + if(curi->size==sz_long && curi->smode==Dreg) insn_n_cycles += 2; break; case i_NEGX: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -988,6 +1148,7 @@ static void gen_opcode (unsigned long in genflags (flag_subx, curi->size, "newv", "src", "0"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->smode, "srcreg", curi->size, "src"); + if(curi->size==sz_long && curi->smode==Dreg) insn_n_cycles += 2; break; case i_NBCD: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -996,19 +1157,42 @@ static void gen_opcode (unsigned long in printf ("\tuae_u16 newv_hi = - (src & 0xF0);\n"); printf ("\tuae_u16 newv;\n"); printf ("\tint cflg;\n"); - printf ("\tif (newv_lo > 9) { newv_lo-=6; newv_hi-=0x10; }\n"); - printf ("\tnewv = newv_hi + (newv_lo & 0xF);"); - printf ("\tcflg = cflg = (newv_hi & 0x1F0) > 0x90;\n"); + printf ("\tif (newv_lo > 9) { newv_lo -= 6; }\n"); + printf ("\tnewv = newv_hi + newv_lo;"); + printf ("\tcflg = (newv & 0x1F0) > 0x90;\n"); + printf ("\tif (cflg) newv -= 0x60;\n"); printf ("\tSET_CFLG (cflg);\n"); duplicate_carry(); - printf ("\tif (cflg) newv -= 0x60;\n"); genflags (flag_zn, curi->size, "newv", "", ""); genastore ("newv", curi->smode, "srcreg", curi->size, "src"); + if(curi->smode==Dreg) insn_n_cycles += 2; break; case i_CLR: genamode (curi->smode, "srcreg", curi->size, "src", 2, 0); + + /* [NP] CLR does a read before the write only on 68000 */ + /* but there's no cycle penalty for doing the read */ + if ( curi->smode != Dreg ) // only if destination is memory + { + if (curi->size==sz_byte) + printf ("\tuae_s8 src = get_byte(srca);\n"); + else if (curi->size==sz_word) + printf ("\tuae_s16 src = get_word(srca);\n"); + else if (curi->size==sz_long) + printf ("\tuae_s32 src = get_long(srca);\n"); + } + genflags (flag_logical, curi->size, "0", "", ""); genastore ("0", curi->smode, "srcreg", curi->size, "src"); + if(curi->size==sz_long) + { + if(curi->smode==Dreg) + insn_n_cycles += 2; + else + insn_n_cycles += 4; + } + if(curi->smode!=Dreg) + insn_n_cycles += 4; break; case i_NOT: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -1016,6 +1200,7 @@ static void gen_opcode (unsigned long in printf ("\tuae_u32 dst = ~src;\n"); genflags (flag_logical, curi->size, "dst", "", ""); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); + if(curi->size==sz_long && curi->smode==Dreg) insn_n_cycles += 2; break; case i_TST: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -1029,6 +1214,7 @@ static void gen_opcode (unsigned long in else printf ("\tsrc &= 31;\n"); printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); + if(curi->dmode==Dreg) insn_n_cycles += 2; break; case i_BCHG: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -1040,6 +1226,7 @@ static void gen_opcode (unsigned long in printf ("\tdst ^= (1 << src);\n"); printf ("\tSET_ZFLG (((uae_u32)dst & (1 << src)) >> src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->dmode==Dreg) insn_n_cycles += 4; break; case i_BCLR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -1051,6 +1238,13 @@ static void gen_opcode (unsigned long in printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst &= ~(1 << src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->dmode==Dreg) insn_n_cycles += 6; + /* [NP] BCLR #n,Dx takes 12 cycles instead of 14 if n<16 */ + if((curi->smode==imm1) && (curi->dmode==Dreg)) + printf ("\tif ( src < 16 ) { m68k_incpc(4); return 12; }\n"); + /* [NP] BCLR Dy,Dx takes 8 cycles instead of 10 if Dy<16 */ + if((curi->smode==Dreg) && (curi->dmode==Dreg)) + printf ("\tif ( src < 16 ) { m68k_incpc(2); return 8; }\n"); break; case i_BSET: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); @@ -1062,6 +1256,7 @@ static void gen_opcode (unsigned long in printf ("\tSET_ZFLG (1 ^ ((dst >> src) & 1));\n"); printf ("\tdst |= (1 << src);\n"); genastore ("dst", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->dmode==Dreg) insn_n_cycles += 4; break; case i_CMPM: case i_CMP: @@ -1069,12 +1264,15 @@ static void gen_opcode (unsigned long in genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); start_brace (); genflags (flag_cmp, curi->size, "newv", "src", "dst"); + if(curi->size==sz_long && curi->dmode==Dreg) + insn_n_cycles += 2; break; case i_CMPA: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); start_brace (); genflags (flag_cmp, sz_long, "newv", "src", "dst"); + insn_n_cycles += 2; break; /* The next two are coded a little unconventional, but they are doing * weird things... */ @@ -1082,27 +1280,48 @@ static void gen_opcode (unsigned long in genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tuaecptr memp = m68k_areg(regs, dstreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); + /* [NP] Use MovepByteNbr to keep track of each access inside a movep */ if (curi->size == sz_word) { - printf ("\tput_byte(memp, src >> 8); put_byte(memp + 2, src);\n"); + printf ("\tMovepByteNbr=1; put_byte(memp, src >> 8); MovepByteNbr=2; put_byte(memp + 2, src);\n"); } else { - printf ("\tput_byte(memp, src >> 24); put_byte(memp + 2, src >> 16);\n"); - printf ("\tput_byte(memp + 4, src >> 8); put_byte(memp + 6, src);\n"); + printf ("\tMovepByteNbr=1; put_byte(memp, src >> 24); MovepByteNbr=2; put_byte(memp + 2, src >> 16);\n"); + printf ("\tMovepByteNbr=3; put_byte(memp + 4, src >> 8); MovepByteNbr=4; put_byte(memp + 6, src);\n"); } + printf ("\tMovepByteNbr=0;\n"); + if(curi->size==sz_long) insn_n_cycles=24; else insn_n_cycles=16; break; case i_MVPMR: printf ("\tuaecptr memp = m68k_areg(regs, srcreg) + (uae_s32)(uae_s16)%s;\n", gen_nextiword ()); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + /* [NP] Use MovepByteNbr to keep track of each access inside a movep */ if (curi->size == sz_word) { - printf ("\tuae_u16 val = (get_byte(memp) << 8) + get_byte(memp + 2);\n"); + //printf ("\tuae_u16 val = (get_byte(memp) << 8) + get_byte(memp + 2);\n"); + printf ("\tuae_u16 val;\n"); + printf ("\tMovepByteNbr=1; val = (get_byte(memp) << 8);\n"); + printf ("\tMovepByteNbr=2; val += get_byte(memp + 2);\n"); } else { - printf ("\tuae_u32 val = (get_byte(memp) << 24) + (get_byte(memp + 2) << 16)\n"); - printf (" + (get_byte(memp + 4) << 8) + get_byte(memp + 6);\n"); + //printf ("\tuae_u32 val = (get_byte(memp) << 24) + (get_byte(memp + 2) << 16)\n"); + //printf (" + (get_byte(memp + 4) << 8) + get_byte(memp + 6);\n"); + printf ("\tuae_u32 val;\n"); + printf ("\tMovepByteNbr=1; val = (get_byte(memp) << 24);\n"); + printf ("\tMovepByteNbr=2; val += (get_byte(memp + 2) << 16);\n"); + printf ("\tMovepByteNbr=3; val += (get_byte(memp + 4) << 8);\n"); + printf ("\tMovepByteNbr=4; val += get_byte(memp + 6);\n"); } + printf ("\tMovepByteNbr=0;\n"); genastore ("val", curi->dmode, "dstreg", curi->size, "dst"); + if(curi->size==sz_long) insn_n_cycles=24; else insn_n_cycles=16; break; case i_MOVE: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); + + /* [NP] genamode counts 2 cycles if dest is -(An), this is wrong. */ + /* For move dest (An), (An)+ and -(An) take the same time */ + /* (for other instr, dest -(An) really takes 2 cycles more) */ + if ( curi->dmode == Apdi ) + insn_n_cycles -= 2; /* correct the wrong cycle count for -(An) */ + genflags (flag_logical, curi->size, "src", "", ""); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); break; @@ -1116,15 +1335,16 @@ static void gen_opcode (unsigned long in } genastore ("val", curi->dmode, "dstreg", sz_long, "dst"); break; - case i_MVSR2: + case i_MVSR2: /* Move from SR */ genamode (curi->smode, "srcreg", sz_word, "src", 2, 0); printf ("\tMakeSR();\n"); if (curi->size == sz_byte) genastore ("regs.sr & 0xff", curi->smode, "srcreg", sz_word, "src"); else genastore ("regs.sr", curi->smode, "srcreg", sz_word, "src"); + if (curi->smode==Dreg) insn_n_cycles += 2; else insn_n_cycles += 4; break; - case i_MV2SR: + case i_MV2SR: /* Move to SR */ genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); if (curi->size == sz_byte) printf ("\tMakeSR();\n\tregs.sr &= 0xFF00;\n\tregs.sr |= src & 0xFF;\n"); @@ -1132,6 +1352,7 @@ static void gen_opcode (unsigned long in printf ("\tregs.sr = src;\n"); } printf ("\tMakeFromSR();\n"); + insn_n_cycles += 8; break; case i_SWAP: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); @@ -1145,6 +1366,7 @@ static void gen_opcode (unsigned long in genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); genastore ("dst", curi->smode, "srcreg", curi->size, "src"); genastore ("src", curi->dmode, "dstreg", curi->size, "dst"); + insn_n_cycles = 6; break; case i_EXT: genamode (curi->smode, "srcreg", sz_long, "src", 1, 0); @@ -1169,7 +1391,7 @@ static void gen_opcode (unsigned long in case i_TRAP: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); sync_m68k_pc (); - printf ("\tException(src+32,0);\n"); + printf ("\tException(src+32,0,M68000_EXC_SRC_CPU);\n"); m68k_pc_offset = 0; break; case i_MVR2USP: @@ -1182,6 +1404,7 @@ static void gen_opcode (unsigned long in break; case i_RESET: printf ("\tcustomreset();\n"); + insn_n_cycles = 132; /* I am not so sure about this!? - Thothy */ break; case i_NOP: break; @@ -1190,6 +1413,7 @@ static void gen_opcode (unsigned long in printf ("\tregs.sr = src;\n"); printf ("\tMakeFromSR();\n"); printf ("\tm68k_setstopped(1);\n"); + insn_n_cycles = 4; break; case i_RTE: if (cpu_level == 0) { @@ -1214,7 +1438,7 @@ static void gen_opcode (unsigned long in printf ("\telse if ((format & 0xF000) == 0x9000) { m68k_areg(regs, 7) += 12; break; }\n"); printf ("\telse if ((format & 0xF000) == 0xa000) { m68k_areg(regs, 7) += 24; break; }\n"); printf ("\telse if ((format & 0xF000) == 0xb000) { m68k_areg(regs, 7) += 84; break; }\n"); - printf ("\telse { Exception(14,0); goto %s; }\n", endlabelstr); + printf ("\telse { Exception(14,0,M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); printf ("\tregs.sr = newsr; MakeFromSR();\n}\n"); pop_braces (old_brace_level); printf ("\tregs.sr = newsr; MakeFromSR();\n"); @@ -1224,9 +1448,9 @@ static void gen_opcode (unsigned long in } /* PC is set and prefetch filled. */ m68k_pc_offset = 0; + insn_n_cycles = 20; break; case i_RTD: - printf ("\tcompiler_flush_jsr_stack();\n"); genamode (Aipi, "7", sz_long, "pc", 1, 0); genamode (curi->smode, "srcreg", curi->size, "offs", 1, 0); printf ("\tm68k_areg(regs, 7) += offs;\n"); @@ -1253,14 +1477,14 @@ static void gen_opcode (unsigned long in printf ("\tm68k_do_rts();\n"); fill_prefetch_0 (); m68k_pc_offset = 0; + insn_n_cycles = 16; break; case i_TRAPV: sync_m68k_pc (); - printf ("\tif (GET_VFLG) { Exception(7,m68k_getpc()); goto %s; }\n", endlabelstr); + printf ("\tif (GET_VFLG) { Exception(7,m68k_getpc(),M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); need_endlabel = 1; break; case i_RTR: - printf ("\tcompiler_flush_jsr_stack();\n"); printf ("\tMakeSR();\n"); genamode (Aipi, "7", sz_word, "sr", 1, 0); genamode (Aipi, "7", sz_long, "pc", 1, 0); @@ -1269,33 +1493,72 @@ static void gen_opcode (unsigned long in fill_prefetch_0 (); printf ("\tMakeFromSR();\n"); m68k_pc_offset = 0; + insn_n_cycles = 20; break; case i_JSR: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); + printf ("\tuaecptr oldpc = m68k_getpc () + %d;\n", m68k_pc_offset); + if (using_exception_3) { + printf ("\tif (srca & 1) {\n"); + printf ("\t\tlast_addr_for_exception_3 = oldpc;\n"); + printf ("\t\tlast_fault_for_exception_3 = srca;\n"); + printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); + printf ("\t}\n"); + need_endlabel = 1; + } printf ("\tm68k_do_jsr(m68k_getpc() + %d, srca);\n", m68k_pc_offset); fill_prefetch_0 (); m68k_pc_offset = 0; + switch(curi->smode) + { + case Aind: insn_n_cycles=16; break; + case Ad16: insn_n_cycles=18; break; + case Ad8r: insn_n_cycles=22; break; + case absw: insn_n_cycles=18; break; + case absl: insn_n_cycles=20; break; + case PC16: insn_n_cycles=18; break; + case PC8r: insn_n_cycles=22; break; + } break; case i_JMP: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); + if (using_exception_3) { + printf ("\tif (srca & 1) {\n"); + printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + %d;\n" , m68k_pc_offset); // [NP] last_addr is not pc+6 + printf ("\t\tlast_fault_for_exception_3 = srca;\n"); + printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); + printf ("\t}\n"); + need_endlabel = 1; + } printf ("\tm68k_setpc(srca);\n"); fill_prefetch_0 (); m68k_pc_offset = 0; + switch(curi->smode) + { + case Aind: insn_n_cycles=8; break; + case Ad16: insn_n_cycles=10; break; + case Ad8r: insn_n_cycles=14; break; + case absw: insn_n_cycles=10; break; + case absl: insn_n_cycles=12; break; + case PC16: insn_n_cycles=10; break; + case PC8r: insn_n_cycles=14; break; + } break; case i_BSR: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); printf ("\tuae_s32 s = (uae_s32)src + 2;\n"); if (using_exception_3) { printf ("\tif (src & 1) {\n"); - printf ("\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); + printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); // [NP] FIXME should be +4, not +2 (same as DBcc) ? printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + s;\n"); - printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); + printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; } printf ("\tm68k_do_bsr(m68k_getpc() + %d, s);\n", m68k_pc_offset); fill_prefetch_0 (); m68k_pc_offset = 0; + insn_n_cycles = 18; break; case i_Bcc: if (curi->size == sz_long) { @@ -1304,7 +1567,7 @@ static void gen_opcode (unsigned long in printf ("\tif (!cctrue(%d)) goto %s;\n", curi->cc, endlabelstr); printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + 1;\n"); - printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); + printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); need_endlabel = 1; } else { if (next_cpu_level < 1) @@ -1315,58 +1578,75 @@ static void gen_opcode (unsigned long in printf ("\tif (!cctrue(%d)) goto didnt_jump;\n", curi->cc); if (using_exception_3) { printf ("\tif (src & 1) {\n"); - printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); + printf ("\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); // [NP] FIXME should be +4, not +2 (same as DBcc) ? printf ("\t\tlast_fault_for_exception_3 = m68k_getpc() + 2 + (uae_s32)src;\n"); - printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); + printf ("\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); printf ("\t}\n"); need_endlabel = 1; } -#ifdef USE_COMPILER - printf ("\tm68k_setpc_bcc(m68k_getpc() + 2 + (uae_s32)src);\n"); -#else printf ("\tm68k_incpc ((uae_s32)src + 2);\n"); -#endif fill_prefetch_0 (); - printf ("\treturn 5;\n"); + printf ("\treturn 10;\n"); printf ("didnt_jump:;\n"); need_endlabel = 1; - insn_n_cycles = curi->size == sz_byte ? 8 : 12; + insn_n_cycles = (curi->size == sz_byte) ? 8 : 12; break; case i_LEA: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 2, 0); genastore ("srca", curi->dmode, "dstreg", curi->size, "dst"); + /* Set correct cycles: According to the M68K User Manual, LEA takes 12 + * cycles in Ad8r and PC8r mode, but it takes 14 (or 16) cycles on a real ST: */ + if (curi->smode == Ad8r || curi->smode == PC8r) + insn_n_cycles = 14; break; case i_PEA: genamode (curi->smode, "srcreg", curi->size, "src", 0, 0); genamode (Apdi, "7", sz_long, "dst", 2, 0); genastore ("srca", Apdi, "7", sz_long, "dst"); + /* Set correct cycles: */ + switch(curi->smode) + { + case Aind: insn_n_cycles=12; break; + case Ad16: insn_n_cycles=16; break; + /* Note: according to the M68K User Manual, PEA takes 20 cycles for + * the Ad8r mode, but on a real ST, it takes 22 (or 24) cycles! */ + case Ad8r: insn_n_cycles=22; break; + case absw: insn_n_cycles=16; break; + case absl: insn_n_cycles=20; break; + case PC16: insn_n_cycles=16; break; + /* Note: PEA with PC8r takes 20 cycles according to the User Manual, + * but it takes 22 (or 24) cycles on a real ST: */ + case PC8r: insn_n_cycles=22; break; + } break; case i_DBcc: genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "offs", 1, 0); - printf ("\tif (!cctrue(%d)) {\n", curi->cc); + printf ("\tif (!cctrue(%d)) {\n\t", curi->cc); genastore ("(src-1)", curi->smode, "srcreg", curi->size, "src"); printf ("\t\tif (src) {\n"); if (using_exception_3) { printf ("\t\t\tif (offs & 1) {\n"); - printf ("\t\t\tlast_addr_for_exception_3 = m68k_getpc() + 2;\n"); + printf ("\t\t\tlast_addr_for_exception_3 = m68k_getpc() + 2 + 2;\n"); // [NP] last_addr is pc+4, not pc+2 printf ("\t\t\tlast_fault_for_exception_3 = m68k_getpc() + 2 + (uae_s32)offs + 2;\n"); - printf ("\t\t\tlast_op_for_exception_3 = opcode; Exception(3,0); goto %s;\n", endlabelstr); + printf ("\t\t\tlast_op_for_exception_3 = opcode; Exception(3,0,M68000_EXC_SRC_CPU); goto %s;\n", endlabelstr); printf ("\t\t}\n"); need_endlabel = 1; } -#ifdef USE_COMPILER - printf ("\t\t\tm68k_setpc_bcc(m68k_getpc() + (uae_s32)offs + 2);\n"); -#else printf ("\t\t\tm68k_incpc((uae_s32)offs + 2);\n"); -#endif fill_prefetch_0 (); - /* ??? Cycle count is a guess. */ - printf ("\t\treturn 6;\n"); - printf ("\t\t}\n"); + printf ("\t\t\treturn 10;\n"); + printf ("\t\t} else {\n\t\t\t"); + { + int tmp_offset = m68k_pc_offset; + sync_m68k_pc(); /* not so nice to call it here... */ + m68k_pc_offset = tmp_offset; + } + printf ("\t\t\treturn 14;\n"); + printf ("\t\t}\n"); printf ("\t}\n"); insn_n_cycles = 12; need_endlabel = 1; @@ -1376,6 +1656,11 @@ static void gen_opcode (unsigned long in start_brace (); printf ("\tint val = cctrue(%d) ? 0xff : 0;\n", curi->cc); genastore ("val", curi->smode, "srcreg", curi->size, "src"); + if (curi->smode!=Dreg) insn_n_cycles += 4; + else + { /* [NP] if result is TRUE, we return 6 instead of 4 */ + printf ("\tif (val) { m68k_incpc(2) ; return 4+2; }\n"); + } break; case i_DIVU: printf ("\tuaecptr oldpc = m68k_getpc();\n"); @@ -1384,7 +1669,7 @@ static void gen_opcode (unsigned long in sync_m68k_pc (); /* Clear V flag when dividing by zero - Alcatraz Odyssey demo depends * on this (actually, it's doing a DIVS). */ - printf ("\tif (src == 0) { SET_VFLG (0); Exception (5, oldpc); goto %s; } else {\n", endlabelstr); + printf ("\tif (src == 0) { SET_VFLG (0); Exception (5, oldpc,M68000_EXC_SRC_CPU); goto %s; } else {\n", endlabelstr); printf ("\tuae_u32 newv = (uae_u32)dst / (uae_u32)(uae_u16)src;\n"); printf ("\tuae_u32 rem = (uae_u32)dst %% (uae_u32)(uae_u16)src;\n"); /* The N flag appears to be set each time there is an overflow. @@ -1395,7 +1680,9 @@ static void gen_opcode (unsigned long in genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); printf ("\t}\n"); printf ("\t}\n"); - insn_n_cycles += 136; +// insn_n_cycles += 136; + printf ("\tretcycles = getDivu68kCycles((uae_u32)dst, (uae_u16)src);\n"); + sprintf(exactCpuCycles," return (%i+retcycles);", insn_n_cycles); need_endlabel = 1; break; case i_DIVS: @@ -1403,7 +1690,7 @@ static void gen_opcode (unsigned long in genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_long, "dst", 1, 0); sync_m68k_pc (); - printf ("\tif (src == 0) { SET_VFLG (0); Exception(5,oldpc); goto %s; } else {\n", endlabelstr); + printf ("\tif (src == 0) { SET_VFLG (0); Exception(5,oldpc,M68000_EXC_SRC_CPU); goto %s; } else {\n", endlabelstr); printf ("\tuae_s32 newv = (uae_s32)dst / (uae_s32)(uae_s16)src;\n"); printf ("\tuae_u16 rem = (uae_s32)dst %% (uae_s32)(uae_s16)src;\n"); printf ("\tif ((newv & 0xffff8000) != 0 && (newv & 0xffff8000) != 0xffff8000) { SET_VFLG (1); SET_NFLG (1); SET_CFLG (0); } else\n\t{\n"); @@ -1413,7 +1700,9 @@ static void gen_opcode (unsigned long in genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); printf ("\t}\n"); printf ("\t}\n"); - insn_n_cycles += 154; +// insn_n_cycles += 154; + printf ("\tretcycles = getDivs68kCycles((uae_s32)dst, (uae_s16)src);\n"); + sprintf(exactCpuCycles," return (%i+retcycles);", insn_n_cycles); need_endlabel = 1; break; case i_MULU: @@ -1423,24 +1712,34 @@ static void gen_opcode (unsigned long in printf ("\tuae_u32 newv = (uae_u32)(uae_u16)dst * (uae_u32)(uae_u16)src;\n"); genflags (flag_logical, sz_long, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); - insn_n_cycles += 66; + /* [NP] number of cycles is 38 + 2n + ea time ; n is the number of 1 bits in src */ + insn_n_cycles += 38-4; /* insn_n_cycles is already initialized to 4 instead of 0 */ + printf ("\twhile (src) { if (src & 1) retcycles++; src = (uae_u16)src >> 1; }\n"); + sprintf(exactCpuCycles," return (%i+retcycles*2);", insn_n_cycles); break; case i_MULS: genamode (curi->smode, "srcreg", sz_word, "src", 1, 0); genamode (curi->dmode, "dstreg", sz_word, "dst", 1, 0); start_brace (); printf ("\tuae_u32 newv = (uae_s32)(uae_s16)dst * (uae_s32)(uae_s16)src;\n"); + printf ("\tuae_u32 src2;\n"); genflags (flag_logical, sz_long, "newv", "", ""); genastore ("newv", curi->dmode, "dstreg", sz_long, "dst"); - insn_n_cycles += 66; + /* [NP] number of cycles is 38 + 2n + ea time ; n is the number of 01 or 10 patterns in src expanded to 17 bits */ + insn_n_cycles += 38-4; /* insn_n_cycles is already initialized to 4 instead of 0 */ + printf ("\tsrc2 = ((uae_u32)src) << 1;\n"); + printf ("\twhile (src2) { if ( ( (src2 & 3) == 1 ) || ( (src2 & 3) == 2 ) ) retcycles++; src2 >>= 1; }\n"); + sprintf(exactCpuCycles," return (%i+retcycles*2);", insn_n_cycles); break; case i_CHK: printf ("\tuaecptr oldpc = m68k_getpc();\n"); genamode (curi->smode, "srcreg", curi->size, "src", 1, 0); genamode (curi->dmode, "dstreg", curi->size, "dst", 1, 0); - printf ("\tif ((uae_s32)dst < 0) { SET_NFLG (1); Exception(6,oldpc); goto %s; }\n", endlabelstr); - printf ("\telse if (dst > src) { SET_NFLG (0); Exception(6,oldpc); goto %s; }\n", endlabelstr); + sync_m68k_pc (); + printf ("\tif ((uae_s32)dst < 0) { SET_NFLG (1); Exception(6,oldpc,M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); + printf ("\telse if (dst > src) { SET_NFLG (0); Exception(6,oldpc,M68000_EXC_SRC_CPU); goto %s; }\n", endlabelstr); need_endlabel = 1; + insn_n_cycles += 6; break; case i_CHK2: @@ -1465,7 +1764,8 @@ static void gen_opcode (unsigned long in } printf ("\tSET_ZFLG (upper == reg || lower == reg);\n"); printf ("\tSET_CFLG (lower <= upper ? reg < lower || reg > upper : reg > upper || reg < lower);\n"); - printf ("\tif ((extra & 0x800) && GET_CFLG) { Exception(6,oldpc); goto %s; }\n}\n", endlabelstr); + sync_m68k_pc (); + printf ("\tif ((extra & 0x800) && GET_CFLG) { Exception(6,oldpc,M68000_EXC_SRC_CPU); goto %s; }\n}\n", endlabelstr); need_endlabel = 1; break; @@ -1481,6 +1781,7 @@ static void gen_opcode (unsigned long in } printf ("\tuae_u32 sign = (%s & val) >> %d;\n", cmask (curi->size), bit_size (curi->size) - 1); printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tval = %s & (uae_u32)-sign;\n", bit_mask (curi->size)); @@ -1501,6 +1802,10 @@ static void gen_opcode (unsigned long in printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ASL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1513,6 +1818,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_VFLG (val != 0);\n"); @@ -1537,6 +1843,10 @@ static void gen_opcode (unsigned long in printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_LSR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1549,6 +1859,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_CFLG ((cnt == %d) & (val >> %d));\n", @@ -1566,6 +1877,10 @@ static void gen_opcode (unsigned long in printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_LSL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1578,6 +1893,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); printf ("\tif (cnt >= %d) {\n", bit_size (curi->size)); printf ("\t\tSET_CFLG (cnt == %d ? val & 1 : 0);\n", @@ -1596,6 +1912,10 @@ static void gen_opcode (unsigned long in printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ROL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1608,6 +1928,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); @@ -1623,6 +1944,10 @@ static void gen_opcode (unsigned long in printf ("}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ROR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1635,6 +1960,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); @@ -1650,6 +1976,10 @@ static void gen_opcode (unsigned long in printf ("\t}\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ROXL: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1662,6 +1992,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); @@ -1680,6 +2011,10 @@ static void gen_opcode (unsigned long in printf ("\tSET_CFLG (GET_XFLG);\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ROXR: genamode (curi->smode, "srcreg", curi->size, "cnt", 1, 0); @@ -1692,6 +2027,7 @@ static void gen_opcode (unsigned long in default: abort (); } printf ("\tcnt &= 63;\n"); + printf ("\tretcycles = cnt;\n"); printf ("\tCLEAR_CZNV;\n"); if (source_is_imm1_8 (curi)) printf ("{"); @@ -1713,6 +2049,10 @@ static void gen_opcode (unsigned long in printf ("\tSET_CFLG (GET_XFLG);\n"); genflags (flag_logical_noclobber, curi->size, "val", "", ""); genastore ("val", curi->dmode, "dstreg", curi->size, "data"); + if(curi->size==sz_long) + strcpy(exactCpuCycles," return (8+retcycles*2);"); + else + strcpy(exactCpuCycles," return (6+retcycles*2);"); break; case i_ASRW: genamode (curi->smode, "srcreg", curi->size, "data", 1, 0); @@ -1961,7 +2301,7 @@ static void gen_opcode (unsigned long in case i_TRAPcc: if (curi->smode != am_unknown && curi->smode != am_illg) genamode (curi->smode, "srcreg", curi->size, "dummy", 1, 0); - printf ("\tif (cctrue(%d)) { Exception(7,m68k_getpc()); goto %s; }\n", curi->cc, endlabelstr); + printf ("\tif (cctrue(%d)) { Exception(7,m68k_getpc(),M68000_EXC_SRC_CPU); goto %s; }\n", curi->cc, endlabelstr); need_endlabel = 1; break; case i_DIVL: @@ -2029,6 +2369,8 @@ static void gen_opcode (unsigned long in break; case i_BFINS: printf ("\ttmp = m68k_dreg(regs, (extra >> 12) & 7);\n"); + printf ("\tSET_NFLG (tmp & (1 << (width - 1)) ? 1 : 0);\n"); + printf ("\tSET_ZFLG (tmp == 0);\n"); break; default: break; @@ -2094,6 +2436,7 @@ static void gen_opcode (unsigned long in genflags (flag_logical, curi->size, "src", "", ""); printf ("\tsrc |= 0x80;\n"); genastore ("src", curi->smode, "srcreg", curi->size, "src"); + if( curi->smode!=Dreg ) insn_n_cycles += 2; break; case i_FPP: genamode (curi->smode, "srcreg", curi->size, "extra", 1, 0); @@ -2144,15 +2487,33 @@ static void gen_opcode (unsigned long in case i_CPUSHA: break; case i_MOVE16: - printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n"); - printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword()); - printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n"); - printf ("\tput_long(memd, get_long(mems));\n"); - printf ("\tput_long(memd+4, get_long(mems+4));\n"); - printf ("\tput_long(memd+8, get_long(mems+8));\n"); - printf ("\tput_long(memd+12, get_long(mems+12));\n"); - printf ("\tm68k_areg(regs, srcreg) += 16;\n"); - printf ("\tm68k_areg(regs, dstreg) += 16;\n"); + if ((opcode & 0xfff8) == 0xf620) { + /* MOVE16 (Ax)+,(Ay)+ */ + printf ("\tuaecptr mems = m68k_areg(regs, srcreg) & ~15, memd;\n"); + printf ("\tdstreg = (%s >> 12) & 7;\n", gen_nextiword()); + printf ("\tmemd = m68k_areg(regs, dstreg) & ~15;\n"); + printf ("\tput_long(memd, get_long(mems));\n"); + printf ("\tput_long(memd+4, get_long(mems+4));\n"); + printf ("\tput_long(memd+8, get_long(mems+8));\n"); + printf ("\tput_long(memd+12, get_long(mems+12));\n"); + printf ("\tif (srcreg != dstreg)\n"); + printf ("\tm68k_areg(regs, srcreg) += 16;\n"); + printf ("\tm68k_areg(regs, dstreg) += 16;\n"); + } else { + /* Other variants */ + genamode (curi->smode, "srcreg", curi->size, "mems", 0, 2); + genamode (curi->dmode, "dstreg", curi->size, "memd", 0, 2); + printf ("\tmemsa &= ~15;\n"); + printf ("\tmemda &= ~15;\n"); + printf ("\tput_long(memda, get_long(memsa));\n"); + printf ("\tput_long(memda+4, get_long(memsa+4));\n"); + printf ("\tput_long(memda+8, get_long(memsa+8));\n"); + printf ("\tput_long(memda+12, get_long(memsa+12));\n"); + if ((opcode & 0xfff8) == 0xf600) + printf ("\tm68k_areg(regs, srcreg) += 16;\n"); + else if ((opcode & 0xfff8) == 0xf608) + printf ("\tm68k_areg(regs, dstreg) += 16;\n"); + } break; case i_MMUOP: @@ -2175,14 +2536,7 @@ static void generate_includes (FILE * f) fprintf (f, "#include \"maccess.h\"\n"); fprintf (f, "#include \"memory.h\"\n"); fprintf (f, "#include \"newcpu.h\"\n"); - fprintf (f, "#include \"compiler.h\"\n"); fprintf (f, "#include \"cputbl.h\"\n"); -/* - fprintf (f, "#include \"sysconfig.h\"\n"); - fprintf (f, "#include \"config.h\"\n"); - fprintf (f, "#include \"options.h\"\n"); - fprintf (f, "#include \"custom.h\"\n"); -*/ fprintf (f, "#define CPUFUNC(x) x##_ff\n" "#ifdef NOFLAGS\n" "#include \"noflags.h\"\n" @@ -2197,6 +2551,8 @@ static void generate_one_opcode (int rp) uae_u16 smsk, dmsk; long int opcode = opcode_map[rp]; + exactCpuCycles[0] = 0; /* Default: not used */ + if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level) return; @@ -2226,6 +2582,7 @@ static void generate_one_opcode (int rp) case 3: smsk = 7; break; case 4: smsk = 7; break; case 5: smsk = 63; break; + case 7: smsk = 3; break; default: abort (); } dmsk = 7; @@ -2287,10 +2644,25 @@ static void generate_one_opcode (int rp) need_endlabel = 0; endlabelno++; sprintf (endlabelstr, "endlabel%d", endlabelno); + if(table68k[opcode].mnemo==i_ASR || table68k[opcode].mnemo==i_ASL || table68k[opcode].mnemo==i_LSR || table68k[opcode].mnemo==i_LSL + || table68k[opcode].mnemo==i_ROL || table68k[opcode].mnemo==i_ROR || table68k[opcode].mnemo==i_ROXL || table68k[opcode].mnemo==i_ROXR + || table68k[opcode].mnemo==i_MVMEL || table68k[opcode].mnemo==i_MVMLE + || table68k[opcode].mnemo==i_MULU || table68k[opcode].mnemo==i_MULS + || table68k[opcode].mnemo==i_DIVU || table68k[opcode].mnemo==i_DIVS ) + printf("\tunsigned int retcycles = 0;\n"); gen_opcode (opcode); if (need_endlabel) printf ("%s: ;\n", endlabelstr); - printf ("return %d;\n", insn_n_cycles / 2); + + if (strlen(exactCpuCycles) > 0) + printf("%s\n",exactCpuCycles); + else + printf ("return %d;\n", insn_n_cycles); + /* Now patch in the instruction cycles at the beginning of the function: */ + fseek(stdout, nCurInstrCycPos, SEEK_SET); + printf("%d;", insn_n_cycles); + fseek(stdout, 0, SEEK_END); + printf ("}\n"); opcode_next_clev[rp] = next_cpu_level; opcode_last_postfix[rp] = postfix; @@ -2313,7 +2685,7 @@ static void generate_func (void) } postfix = i; - fprintf (stblfile, "struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); + fprintf (stblfile, "const struct cputbl CPUFUNC(op_smalltbl_%d)[] = {\n", postfix); /* sam: this is for people with low memory (eg. me :)) */ printf ("\n" @@ -2363,7 +2735,10 @@ int main (int argc, char **argv) headerfile = fopen ("cputbl.h", "wb"); stblfile = fopen ("cpustbl.c", "wb"); - freopen ("cpuemu.c", "wb", stdout); + if (freopen ("cpuemu.c", "wb", stdout) == NULL) { + perror("cpuemu.c"); + return -1; + } generate_includes (stdout); generate_includes (stblfile);