/******************************************************************************
*
* project name:    TIGCC Tools Suite
* file name:       ttdasm.c
* initial date:    11/09/2000
* author:          thomas.nussbaumer@gmx.net
*                  rusty@acz.org (original VTI code)
* description:     TI89/92+ executable and ROM disassembler
*
* CREDITS: this tool is based on code from VTI (author: Rusty Wagner)
*
* $Id: ttdasm.c,v 1.6 2002/02/07 09:49:37 tnussb Exp $
*
******************************************************************************/

//--------------------------------------------------------
// TODO:
//
//  (1) relocation of NOSTUB and (???) DOORS ASM files
//  (2) using labels (!!!) instead of addresses
//  (3) compile-able output
//  (4) using VTI save file as input
//  (5) flags for binary input (no standard TI file)
//
//--------------------------------------------------------



#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "ttversion.h"
#include "revtools.h"
#include "tt.h"

#ifdef CVS_FILE_REVISION
#undef CVS_FILE_REVISION
#endif

//-----------------------------------------------------------------------------
// DON'T EDIT THE NEXT DEFINE BY HAND! THIS IS DONE AUTOMATICALLY BY THE
// CVS SYSTEM !!!
//-----------------------------------------------------------------------------
#define CVS_FILE_REVISION "$Revision: 1.6 $"


//=============================================================================
// outputs usage information of this tool
//=============================================================================
void PrintUsage() {
    fprintf(USAGE_OUT, "Usage: ttdasm [flags] [<infile>]\n\n"                             \
                       "       -o <number>       ... use given offset as start point\n"   \
                       "       -l <bytes>        ... disassemble number of given bytes\n" \
                       "       -r <romfile>      ... disassemble given rom file\n"        \
                       "       -f                ... show ROM function table\n"           \
                       "       -name             ... show possible ROM calls\n"           \
                       "       -virtual <number> ... use additionally virtual offset\n"   \
                       "       -nolabels         ... use no labels in output\n"           \
                       "       -raw              ... treat file as raw binary\n"          \
                       "       -vti              ... treat file as VTI save file\n"       \
                       "       -stub             ... prints additionally information of\n"\
                       "                             kernel based programs\n\n"           \
                       "       disassembles a TI89/TI92plus NOSTUB executable,\n"         \
                       "       a TI89/TI92plus raw dump,parts of a given ROM file or\n"   \
                       "       a VTI save file.\n\n"                                      \
                       "       NOTE1: the offset and the length can be specified as\n"    \
                       "              hex numbers, too (for example: -o 0x4c)\n\n"        \
                       "       NOTE2: offsets are not treated as pure file offsets,\n"    \
                       "              but are handled depending on the target.\n"         \
                       "              Within executables offset 0 starts at file offset\n"\
                       "              88 which is just behind the header and the length\n"\
                       "              information. Offsets within ROM files maps\n"       \
                       "              directly to the real addresses within the calculator.\n\n");
}


unsigned char* rom;
unsigned char* ram;
int            initialPC;
int            initIntTabOfs;
unsigned char* mem[256];
unsigned char  garbagemem[0x10000];
int            label_parse = 0;
int            no_labels   = 0;

typedef struct {
    int   num;
    char *name;
} ROMFunc;


ROMFunc romFuncs[]=
   {{0,"FirstWindow"},{1,"WinActivate"},{2,"WinAttr"},{3,"WinBackupToScr"},{4,"WinBackground"},
    {5,"WinBegin"},{6,"WinBitmapGet"},{7,"WinBitmapPut"},{8,"WinBitmapSize"},{9,"WinCharXY"},{0xa,"WinChar"},
    {0xb,"WinClose"},{0xc,"WinClr"},{0xd,"WinDeactivate"},{0xe,"WinDupStat"},{0xf,"WinEllipse"},{0x10,"WinFill"},
    {0x11,"WinFillLines2"},{0x12,"WinFillTriangle"},{0x13,"WinFont"},{0x14,"WinGetCursor"},{0x15,"WinHide"},
    {0x16,"WinHome"},{0x17,"WinLine"},{0x18,"WinLineNC"},{0x19,"WinLineTo"},{0x1a,"WinLineRel"},{0x1b,"WinMoveCursor"},
    {0x1c,"WinMoveTo"},{0x1d,"WinMoveRel"},{0x1e,"WinOpen"},{0x1f,"WinPixGet"},{0x20,"WinPixSet"},{0x21,"WinRect"},
    {0x22,"WinReOpen"},{0x23,"WinScrollH"},{0x24,"WinScrollV"},{0x25,"WinStr"},{0x26,"WinStrXY"},{0x27,"DrawWinBorder"},
    {0x28,"ScrRectDivide"},{0x29,"RectWinToWin"},{0x2a,"RectWinToScr"},{0x2b,"UpdateWindows"},{0x2c,"MakeWinRect"},
    {0x2d,"ScrToWin"},{0x2e,"ScrToHome"},{0x2f,"ScrRect"},{0x30,"Dialog"},{0x31,"NoCallBack"},{0x32,"DialogDo"},
    {0x33,"DialogAdd"},{0x34,"DialogNew"},{0x35,"DrawStaticButton"},{0x36,"MenuBegin"},{0x37,"MenuCheck"},
    {0x38,"MenuEnd"},{0x39,"MenuKey"},{0x3a,"MenuOn"},{0x3b,"MenuPopup"},{0x3c,"MenuSubStat"},{0x3d,"MenuTopStat"},
    {0x3e,"MenuTopSelect"},{0x3f,"MenuTopRedef"},{0x40,"MenuGetTopRedef"},{0x41,"MenuAddText"},{0x42,"MenuAddIcon"},
    {0x43,"MenuNew"},{0x44,"PopupAddText"},{0x45,"PopupNew"},{0x46,"PopupClear"},{0x47,"PopupDo"},{0x48,"PopupText"},
    {0x49,"MenuUpdate"},{0x4a,"Parse2DExpr"},{0x4b,"Parse2DMultiExpr"},{0x4c,"Print2DExpr"},{0x4d,"Parms2D"},
    {0x4e,"display_statements"},{0x4f,"Parse1DExpr"},{0x50,"pushkey"},{0x51,"ngetchx"},{0x52,"kbhit"},
    {0x53,"sprintf"},{0x54,"getcalc"},{0x55,"sendcalc"},{0x56,"LIO_Send"},{0x57,"LIO_Get"},{0x58,"LIO_Receive"},
    {0x59,"LIO_GetMultiple"},{0x5a,"LIO_SendData"},{0x5b,"LIO_RecvData"},{0x5c,"SymAdd"},{0x5d,"SymAddMain"},
    {0x5e,"SymDel"},{0x5f,"HSymDel"},{0x60,"SymFind"},{0x61,"SymFindMain"},{0x62,"SymFindHome"},{0x63,"SymMove"},
    {0x64,"FolderAdd"},{0x65,"FolderCur"},{0x66,"FolderDel"},{0x67,"FolderFind"},{0x68,"FolderGetCur"},{0x69,"FolderOp"},
    {0x6a,"FolderRename"},{0x6b,"FolderCount"},{0x6c,"SymFindFirst"},{0x6d,"SymFindNext"},{0x6e,"SymFindPrev"},
    {0x6f,"SymFindFoldername"},{0x70,"AddSymToFolder"},{0x71,"FindSymInFolder"},{0x72,"FolderCurTemp"},
    {0x73,"FolderAddTemp"},{0x74,"FolderDelTemp"},{0x75,"FolderDelAllTemp"},{0x76,"TempFolderName"},
    {0x77,"IsMainFolderStr"},{0x78,"ParseSymName"},{0x79,"DerefSym"},{0x7a,"HSYMtoName"},{0x7b,"StrToTokN"},
    {0x7c,"TokToStrN"},{0x7d,"CheckGraphRef"},{0x7e,"ClearUserDef"},{0x7f,"CheckLinkLockFlag"},{0x80,"TokenizeSymName"},
    {0x81,"SymCmp"},{0x82,"SymCpy"},{0x83,"SymCpy0"},{0x84,"ValidateSymName"},{0x85,"VarRecall"},{0x86,"VarStore"},
    {0x87,"VarStoreLink"},{0x88,"QSysProtected"},{0x89,"CheckSysFunc"},{0x8a,"GetSysGraphRef"},{0x8b,"CheckReservedName"},
    {0x8c,"SymSysVar"},{0x8d,"ValidateStore"},{0x8e,"ResetSymFlags"},{0x8f,"HeapAvail"},{0x90,"HeapAlloc"},
    {0x91,"HeapAllocESTACK"},{0x92,"HeapAllocHigh"},{0x93,"HeapAllocThrow"},{0x94,"HeapAllocHighThrow"},
    {0x95,"HeapCompress"},{0x96,"HeapDeref"},{0x97,"HeapFree"},{0x98,"HeapFreeIndir"},{0x99,"HLock"},{0x9a,"HeapLock"},
    {0x9b,"HeapGetLock"},{0x9c,"HeapMax"},{0x9d,"HeapRealloc"},{0x9e,"HeapSize"},{0x9f,"HeapUnlock"},{0xa0,"HeapMoveHigh"},
    {0xa1,"HeapEnd"},{0xa2,"HeapAllocPtr"},{0xa3,"HeapFreePtr"},{0xa4,"NeedStack"},{0xa5,"TE_close"},
    {0xa6,"TE_checkSlack"},{0xa7,"TE_empty"},{0xa8,"TE_focus"},{0xa9,"TE_handleEvent"},{0xaa,"TE_indicateReadOnly"},
    {0xab,"TE_isBlank"},{0xac,"TE_open"},{0xad,"TE_openFixed"},{0xae,"TE_pasteText"},{0xaf,"TE_reopen"},
    {0xb0,"TE_reopenPlain"},{0xb1,"TE_select"},{0xb2,"TE_shrinkWrap"},{0xb3,"TE_unfocus"},{0xb4,"TE_updateCommand"},
    {0xb5,"_bcd_math"},{0xb6,"bcdadd"},{0xb7,"bcdsub"},{0xb8,"bcdmul"},{0xb9,"bcddiv"},{0xba,"bcdneg"},{0xbb,"bcdcmp"},
    {0xbc,"bcdlong"},{0xbd,"bcdbcd"},{0xbe,"EX_getArg"},{0xbf,"EX_getBCD"},{0xc0,"EX_stoBCD"},
    {0xc1,"CB_replaceTEXT"},{0xc2,"CB_fetchTEXT"},{0xc3,"CU_restore"},{0xc4,"CU_start"},{0xc5,"CU_stop"},
    {0xc6,"EV_captureEvents"},{0xc7,"EV_clearPasteString"},{0xc8,"EV_getc"},{0xc9,"EV_getSplitRect"},
    {0xca,"EV_notifySwitchGraph"},{0xcb,"EV_paintOneWindow"},{0xcc,"EV_paintWindows"},{0xcd,"EV_restorePainting"},
    {0xce,"EV_sendEvent"},{0xcf,"EV_sendEventSide"},{0xd0,"EV_sendString"},{0xd1,"EV_setCmdCheck"},
    {0xd2,"EV_setCmdState"},{0xd3,"EV_setFKeyState"},{0xd4,"EV_startApp"},{0xd5,"EV_startSide"},{0xd6,"EV_startTask"},
    {0xd7,"EV_suspendPainting"},{0xd8,"EV_switch"},{0xd9,"MO_currentOptions"},{0xda,"MO_defaults"},
    {0xdb,"MO_digestOptions"},{0xdc,"MO_isMultigraphTask"},{0xdd,"MO_modeDialog"},{0xde,"MO_notifyModeChange"},
    {0xdf,"MO_sendQuit"},{0xe0,"ST_angle"},{0xe1,"ST_batt"},{0xe2,"ST_busy"},{0xe3,"ST_eraseHelp"},{0xe4,"ST_folder"},
    {0xe5,"ST_graph"},{0xe6,"ST_helpMsg"},{0xe7,"ST_modKey"},{0xe8,"ST_precision"},{0xe9,"ST_readOnly"},{0xea,"ST_stack"},
    {0xeb,"ST_refDsp"},{0xec,"OSCheckBreak"},{0xed,"OSClearBreak"},{0xee,"OSEnableBreak"},{0xef,"OSDisableBreak"},
    {0xf0,"OSRegisterTimer"},{0xf1,"OSFreeTimer"},{0xf2,"OSTimerCurVal"},{0xf3,"OSTimerExpired"},{0xf4,"OSTimerRestart"},
    {0xf5,"acos"},{0xf6,"asin"},{0xf7,"atan"},{0xf8,"atan2"},{0xf9,"cos"},{0xfa,"sin"},{0xfb,"tan"},{0xfc,"cosh"},
    {0xfd,"sinh"},{0xfe,"tanh"},{0xff,"exp"},{0x100,"log"},{0x101,"log10"},{0x102,"modf"},{0x103,"pow"},
    {0x104,"sqrt"},{0x105,"ceil"},{0x106,"fabs"},{0x107,"floor"},{0x108,"fmod"},{0x109,"top_estack"},
    {0x10a,"next_expression_index"},{0x10b,"gr_active"},{0x10c,"gr_other"},{0x10d,"ABT_dialog"},{0x10e,"HomeExecute"},
    {0x10f,"HomePushEStack"},{0x110,"SP_Define"},{0x111,"store_data_var"},{0x112,"recall_data_var"},{0x113,"CharNumber"},
    {0x114,"spike_optionD"},{0x115,"spike_geo_titles"},{0x116,"spike_in_editor"},{0x117,"dv_create_graph_titles"},
    {0x118,"spike_titles_in_editor"},{0x119,"dv_findColumn"},{0x11a,"spike_chk_gr_dirty"},{0x11b,"GetStatValue"},
    {0x11c,"partial_len"},{0x11d,"paint_all_except"},{0x11e,"EQU_select"},{0x11f,"EQU_setStyle"},{0x120,"EQU_getNameInfo"},
    {0x121,"checkCurrent"},{0x122,"BN_power17Mod"},{0x123,"BN_powerMod"},{0x124,"BN_prodMod"},{0x125,"CAT_dialog"},
    {0x126,"caddcert"},{0x127,"cdecrypt"},{0x128,"ceof"},{0x129,"cfindcertfield"},{0x12a,"cfindfield"},{0x12b,"cgetc"},
    {0x12c,"cgetcert"},{0x12d,"cgetflen"},{0x12e,"cgetfnl"},{0x12f,"cgetnl"},{0x130,"cgetns"},
    {0x131,"cgetvernum"},{0x132,"copen"},{0x133,"copensub"},{0x134,"cputhdr"},{0x135,"cputnl"},{0x136,"cputns"},
    {0x137,"cread"},{0x138,"ctell"},{0x139,"cwrite"},{0x13a,"cacos"},{0x13b,"casin"},{0x13c,"catan"},{0x13d,"cacosh"},
    {0x13e,"casinh"},{0x13f,"catanh"},{0x140,"ccos"},{0x141,"csin"},{0x142,"ctan"},{0x143,"ccosh"},
    {0x144,"csinh"},{0x145,"ctanh"},{0x146,"csqrt"},{0x147,"cln"},{0x148,"clog10"},{0x149,"cexp"},
    {0x14a,"CustomBegin"},{0x14b,"CustomMenuItem"},{0x14c,"CustomEnd"},{0x14d,"ReallocExprStruct"},
    {0x14e,"SearchExprStruct"},{0x14f,"handleRclKey"},{0x150,"CustomFree"},{0x151,"ERD_dialog"},
    {0x152,"ERD_process"},{0x153,"ER_throwVar"},{0x154,"ER_catch"},{0x155,"ER_success"},{0x156,"EV_centralDispatcher"},
    {0x157,"EV_defaultHandler"},{0x158,"EV_eventLoop"},{0x159,"EV_registerMenu"},{0x15a,"EX_patch"},{0x15b,"EM_abandon"},
    {0x15c,"EM_blockErase"},{0x15d,"EM_blockVerifyErase"},{0x15e,"EM_delete"},{0x15f,"EM_findEmptySlot"},
    {0x160,"EM_GC"},{0x161,"EM_moveSymFromExtMem"},{0x162,"EM_moveSymToExtMem"},{0x163,"EM_open"},{0x164,"EM_put"},
    {0x165,"EM_survey"},{0x166,"EM_twinSymFromExtMem"},{0x167,"EM_write"},{0x168,"EM_writeToExtMem"},{0x169,"FL_addCert"},
    {0x16a,"FL_download"},{0x16b,"FL_getHardwareParmBlock"},{0x16c,"FL_getCert"},{0x16d,"FL_getVerNum"},
    {0x16e,"EQU_deStatus"},{0x16f,"cmpstri"},{0x170,"fix_loop_displacements"},{0x171,"FL_write"},{0x172,"fpisanint"},
    {0x173,"fpisodd"},{0x174,"round12"},{0x175,"round14"},{0x176,"GD_Circle"},{0x177,"GD_Line"},{0x178,"GD_HVLine"},
    {0x179,"GD_Pen"},{0x17a,"GD_Eraser"},{0x17b,"GD_Text"},{0x17c,"GD_Select"},{0x17d,"GD_Contour"},{0x17e,"GKeyIn"},
    {0x17f,"GKeyDown"},{0x180,"GKeyFlush"},{0x181,"HelpKeys"},{0x182,"QModeKey"},{0x183,"QSysKey"},{0x184,"WordInList"},
    {0x185,"BitmapGet"},{0x186,"BitmapInit"},{0x187,"BitmapPut"},{0x188,"BitmapSize"},{0x189,"ScrRectFill"},
    {0x18a,"ScrRectOverlap"},{0x18b,"ScrRectScroll"},{0x18c,"ScrRectShift"},{0x18d,"QScrRectOverlap"},
    {0x18e,"FontGetSys"},{0x18f,"FontSetSys"},{0x190,"FontCharWidth"},{0x191,"DrawClipChar"},
    {0x192,"DrawClipEllipse"},{0x193,"DrawClipLine"},{0x194,"DrawClipPix"},{0x195,"DrawClipRect"},
    {0x196,"DrawMultiLines"},{0x197,"DrawStrWidth"},{0x198,"FillTriangle"},{0x199,"FillLines2"},
    {0x19a,"SetCurAttr"},{0x19b,"SetCurClip"},{0x19c,"LineTo"},{0x19d,"MoveTo"},
    {0x19e,"ScreenClear"},{0x19f,"GetPix"},{0x1a0,"SaveScrState"},{0x1a1,"RestoreScrState"},
    {0x1a2,"PortSet"},{0x1a3,"PortRestore"},{0x1a4,"DrawChar"},{0x1a5,"DrawFkey"},{0x1a6,"DrawIcon"},{0x1a7,"DrawLine"},
    {0x1a8,"DrawPix"},{0x1a9,"DrawStr"},{0x1aa,"GM_Value"},{0x1ab,"GM_Intersect"},{0x1ac,"GM_Integrate"},
    {0x1ad,"GM_Inflection"},{0x1ae,"GM_TanLine"},{0x1af,"GM_Math1"},{0x1b0,"GM_Derivative"},{0x1b1,"GM_DistArc"},
    {0x1b2,"GM_Shade"},{0x1b3,"YCvtFtoWin"},{0x1b4,"DlgMessage"},{0x1b5,"SetGraphMode"},
    {0x1b6,"Regraph"},{0x1b7,"GrAxes"},{0x1b8,"gr_xres_pixel"},{0x1b9,"CptFuncX"},{0x1ba,"XCvtPtoF"},{0x1bb,"YCvtPtoF"},
    {0x1bc,"YCvtFtoP"},{0x1bd,"XCvtFtoP"},{0x1be,"GrLineFlt"},{0x1bf,"FuncLineFlt"},{0x1c0,"GrClipLine"},
    {0x1c1,"CptDeltax"},{0x1c2,"CptDeltay"},{0x1c3,"CkValidDelta"},{0x1c4,"GR_Pan"},{0x1c5,"FindFunc"},
    {0x1c6,"FindGrFunc"},{0x1c7,"grFuncName"},{0x1c8,"gr_initCondName"},{0x1c9,"CptIndep"},
    {0x1ca,"gr_CptIndepInc"},{0x1cb,"gr_del_locals"},{0x1cc,"gr_DelFolder"},{0x1cd,"gr_openFolder"},
    {0x1ce,"setup_more_graph_fun"},{0x1cf,"unlock_more_graph_fun"},{0x1d0,"execute_graph_func"},
    {0x1d1,"cpt_gr_fun"},{0x1d2,"cpt_gr_param"},{0x1d3,"cpt_gr_polar"},{0x1d4,"gr_execute_seq"},
    {0x1d5,"CountGrFunc"},{0x1d6,"FirstSeqPlot"},{0x1d7,"cleanup_seq_mem"},{0x1d8,"time_loop"},
    {0x1d9,"InitTimeSeq"},{0x1da,"seqWebInit"},{0x1db,"run_one_seq"},{0x1dc,"gr_seq_value"},
    {0x1dd,"StepCk"},{0x1de,"seqStepCk"},{0x1df,"rngLen"},{0x1e0,"gdb_len"},{0x1e1,"gdb_store"},{0x1e2,"gdb_recall"},
    {0x1e3,"gr_DispLabels"},{0x1e4,"GraphOrTableCmd"},{0x1e5,"ck_valid_float"},{0x1e6,"CreateEmptyList"},
    {0x1e7,"QSkipGraphErr"},{0x1e8,"gr_find_de_result"},{0x1e9,"InitDEAxesRng"},{0x1ea,"InitDEMem"},
    {0x1eb,"de_loop"},{0x1ec,"cleanup_de_mem"},{0x1ed,"gr_de_value"},{0x1ee,"gr_find_func_index"},
    {0x1ef,"CptLastIndepDE"},{0x1f0,"de_initRes"},{0x1f1,"gr_del_vars_in_folder"},{0x1f2,"gr_de_axes_lbl"},
    {0x1f3,"gr_execute_de"},{0x1f4,"gr_delete_fldpic"},{0x1f5,"gr_remove_fldpic"},{0x1f6,"gr_add_fldpic"},
    {0x1f7,"gr_stopic"},{0x1f8,"gr_find_el"},{0x1f9,"deStepCk"},{0x1fa,"gr_ck_solvergraph"},{0x1fb,"GR3_addContours"},
    {0x1fc,"GraphActivate"},{0x1fd,"GR3_freeDB"},{0x1fe,"GR3_handleEvent"},{0x1ff,"GR3_paint3d"},
    {0x200,"GR3_xyToWindow"},{0x201,"GS_PlotTrace"},{0x202,"GS_PlotAll"},{0x203,"PlotDel"},
    {0x204,"PlotPut"},{0x205,"PlotGet"},{0x206,"PlotInit"},{0x207,"PlotDup"},{0x208,"PlotSize"},
    {0x209,"PlotLookup"},{0x20a,"QActivePlots"},{0x20b,"QPlotActive"},{0x20c,"GT_BackupToScr"},{0x20d,"GT_CalcDepVals"},
    {0x20e,"GT_CenterGraphCursor"},{0x20f,"GT_CursorKey"},{0x210,"GT_DspFreeTraceCoords"},
    {0x211,"GT_DispTraceCoords"},{0x212,"GT_DspMsg"},{0x213,"GT_Error"},{0x214,"GT_Format"},
    {0x215,"GT_FreeTrace"},{0x216,"GT_IncXY"},{0x217,"GT_KeyIn"},{0x218,"GT_QFloatCursorsInRange"},
    {0x219,"GT_Regraph"},{0x21a,"GT_Regraph_if_neccy"},{0x21b,"GT_Open"},{0x21c,"GT_SaveAs"},
    {0x21d,"GT_SelFunc"},{0x21e,"GT_SetGraphRange"},{0x21f,"GT_SetCursorXY"},{0x220,"GT_ShowMarkers"},
    {0x221,"GT_Trace"},{0x222,"GT_ValidGraphRanges"},{0x223,"GT_WinBound"},{0x224,"GT_WinCursor"},
    {0x225,"GYcoord"},{0x226,"GXcoord"},{0x227,"round12_err"},{0x228,"GT_Set_Graph_Format"},
    {0x229,"GT_PrintCursor"},{0x22a,"GT_DE_Init_Conds"},{0x22b,"GZ_Box"},{0x22c,"GZ_Center"},{0x22d,"GZ_Decimal"},
    {0x22e,"GZ_Fit"},{0x22f,"GZ_InOut"},{0x230,"Integer"},{0x231,"GZ_Previous"},{0x232,"GZ_Recall"},
    {0x233,"GZ_SetFactors"},{0x234,"GZ_Square"},{0x235,"GZ_Standard"},{0x236,"GZ_Stat"},
    {0x237,"GZ_Store"},{0x238,"GZ_Trig"},{0x239,"HeapGetHandle"},{0x23a,"HeapPtrToHandle"},
    {0x23b,"FreeHandles"},{0x23c,"HS_chopFIFO"},{0x23d,"HS_countFIFO"},{0x23e,"HS_deleteFIFONode"},
    {0x23f,"HS_freeAll"},{0x240,"HS_freeFIFONode"},{0x241,"HS_getAns"},{0x242,"HS_getEntry"},
    {0x243,"HS_getFIFONode"},{0x244,"HS_popEStack"},{0x245,"HS_newFIFONode"},{0x246,"HS_pushFIFONode"},
    {0x247,"HtoESI"},{0x248,"OSInitKeyInitDelay"},{0x249,"OSInitBetweenKeyDelay"},{0x24a,"OSCheckSilentLink"},
    {0x24b,"OSLinkCmd"},{0x24c,"OSLinkReset"},{0x24d,"OSLinkOpen"},{0x24e,"OSLinkClose"},{0x24f,"OSReadLinkBlock"},
    {0x250,"OSWriteLinkBlock"},{0x251,"OSLinkTxQueueInquire"},{0x252,"OSLinkTxQueueActive"},{0x253,"LIO_SendProduct"},
    {0x254,"MD5Init"},{0x255,"MD5Update"},{0x256,"MD5Final"},{0x257,"MD5Done"},{0x258,"convert_to_TI_92"},
    {0x259,"gen_version"},{0x25a,"is_executable"},{0x25b,"NG_RPNToText"},{0x25c,"NG_approxESI"},
    {0x25d,"NG_execute"},{0x25e,"NG_graphESI"},{0x25f,"NG_rationalESI"},{0x260,"NG_tokenize"},
    {0x261,"NG_setup_graph_fun"},{0x262,"NG_cleanup_graph_fun"},{0x263,"push_END_TAG"},{0x264,"push_LIST_TAG"},
    {0x265,"tokenize_if_TI_92_or_text"},{0x266,"setjmp"},{0x267,"longjmp"},{0x268,"VarGraphRefBitsClear"},
    {0x269,"VarInit"},{0x26a,"memcpy"},{0x26b,"memmove"},{0x26c,"strcpy"},{0x26d,"strncpy"},{0x26e,"strcat"},
    {0x26f,"strncat"},{0x270,"memcmp"},{0x271,"strcmp"},{0x272,"strncmp"},{0x273,"memchr"},{0x274,"strchr"},
    {0x275,"strcspn"},{0x276,"strpbrk"},{0x277,"strrchr"},{0x278,"strspn"},{0x279,"strstr"},{0x27a,"strtok"},
    {0x27b,"_memset"},{0x27c,"memset"},{0x27d,"strerror"},{0x27e,"strlen"},{0x27f,"SymAddTwin"},
    {0x280,"SymDelTwin"},{0x281,"LoadSymFromFindHandle"},{0x282,"MakeHsym"},{0x283,"SymFindPtr"},
    {0x284,"OSVRegisterTimer"},{0x285,"OSVFreeTimer"},{0x286,"sincos"},{0x287,"asinh"},{0x288,"acosh"},
    {0x289,"atanh"},{0x28a,"itrig"},{0x28b,"trig"},{0x28c,"VarOpen"},{0x28d,"VarSaveAs"},
    {0x28e,"VarNew"},{0x28f,"VarCreateFolderPopup"},{0x290,"VarSaveTitle"},{0x291,"WinWidth"},
    {0x292,"WinHeight"},{0x293,"XR_stringPtr"},{0x294,"OSReset"},{0x295,"SumStoChkMem"},
    {0x296,"OSContrastUp"},{0x297,"OSContrastDn"},{0x298,"OSKeyScan"},{0x299,"OSGetStatKeys"},
    {0x29a,"off"},{0x29b,"idle"},{0x29c,"OSSetSR"},{0x29d,"AB_prodid"},{0x29e,"AB_prodname"},
    {0x29f,"AB_serno"},{0x2a0,"cgetcertrevno"},{0x2a1,"cgetsn"},{0x2a2,"de_rng_no_graph"},
    {0x2a3,"EV_hook"},{0x2a4,"_ds16u16"},{0x2a5,"_ms16u16"},{0x2a6,"_du16u16"},{0x2a7,"_mu16u16"},{0x2a8,"_ds32s32"},
    {0x2a9,"_ms32s32"},{0x2aa,"_du32u32"},{0x2ab,"_mu32u32"},{0x2ac,"assign_between"},
    {0x2ad,"did_push_var_val"},{0x2ae,"does_push_fetch"},{0x2af,"delete_list_element"},{0x2b0,"push_ans_entry"},
    {0x2b1,"index_after_match_endtag"},{0x2b2,"push_indir_name"},{0x2b3,"push_user_func"},{0x2b4,"store_func_def"},
    {0x2b5,"store_to_subscripted_element"},{0x2b6,"index_below_display_expression"},
    {0x2b7,"get_key_ptr"},{0x2b8,"get_list_indicies"},{0x2b9,"get_matrix_indicies"},{0x2ba,"init_list_indicies"},
    {0x2bb,"init_matrix_indicies"},{0x2bc,"push_float_qr_fact"},{0x2bd,"push_lu_fact"},{0x2be,"push_symbolic_qr_fact"},
    {0x2bf,"are_expressions_identical"},{0x2c0,"compare_expressions"},{0x2c1,"find_error_message"},
    {0x2c2,"check_estack_size"},{0x2c3,"delete_between"},{0x2c4,"deleted_between"},{0x2c5,"delete_expression"},
    {0x2c6,"deleted_expression"},{0x2c7,"estack_to_short"},{0x2c8,"estack_to_ushort"},{0x2c9,"factor_base_index"},
    {0x2ca,"factor_exponent_index"},{0x2cb,"GetValue"},{0x2cc,"im_index"},{0x2cd,"index_numeric_term"},
    {0x2ce,"index_of_lead_base_of_lead_term"},{0x2cf,"index_main_var"},{0x2d0,"is_advanced_tag"},
    {0x2d1,"is_antisymmetric"},{0x2d2,"is_complex_number"},{0x2d3,"is_complex0"},{0x2d4,"is_free_of_tag"},
    {0x2d5,"is_independent_of"},{0x2d6,"is_independent_of_de_seq_vars"},{0x2d7,"is_independent_of_tail"},
    {0x2d8,"is_independent_of_elements"},{0x2d9,"is_monomial"},{0x2da,"is_monomial_in_kernel"},
    {0x2db,"is_narrowly_independent_of"},{0x2dc,"is_symmetric"},{0x2dd,"is_tail_independent_of"},{0x2de,"lead_base_index"},
    {0x2df,"lead_exponent_index"},{0x2e0,"lead_factor_index"},{0x2e1,"lead_term_index"},{0x2e2,"main_gen_var_index"},
    {0x2e3,"map_unary_over_comparison"},{0x2e4,"min_quantum"},{0x2e5,"move_between_to_top"},
    {0x2e6,"moved_between_to_top"},{0x2e7,"numeric_factor_index"},{0x2e8,"push_between"},{0x2e9,"push_expr_quantum"},
    {0x2ea,"push_expr2_quantum"},{0x2eb,"push_next_arb_int"},{0x2ec,"push_next_arb_real"},
    {0x2ed,"push_next_internal_var"},{0x2ee,"push_quantum"},{0x2ef,"push_quantum_pair"},
    {0x2f0,"reductum_index"},{0x2f1,"remaining_factors_index"},{0x2f2,"re_index"},{0x2f3,"reset_estack_size"},
    {0x2f4,"reset_control_flags"},{0x2f5,"can_be_approxed"},{0x2f6,"compare_complex_magnitudes"},
    {0x2f7,"compare_Floats"},{0x2f8,"did_push_cnvrt_Float_to_integer"},{0x2f9,"estack_number_to_Float"},
    {0x2fa,"float_class"},{0x2fb,"frexp10"},{0x2fc,"gcd_exact_whole_Floats"},{0x2fd,"init_float"},
    {0x2fe,"is_Float_exact_whole_number"},{0x2ff,"is_float_infinity"},{0x300,"is_float_negative_zero"},
    {0x301,"is_float_positive_zero"},{0x302,"is_float_signed_infintiy"},{0x303,"is_float_transfinite"},
    {0x304,"is_float_unsigned_inf_or_nan"},{0x305,"is_float_unsigned_zero"},{0x306,"is_nan"},
    {0x307,"likely_approx_to_complex_number"},{0x308,"likely_approx_to_number"},
    {0x309,"norm1_complex_Float"},{0x30a,"push_Float"},{0x30b,"push_Float_to_nonneg_int"},
    {0x30c,"push_Float_to_rat"},{0x30d,"push_cvrt_integer_if_whole_nmb"},{0x30e,"push_overflow_to_infinity"},
    {0x30f,"push_pow"},{0x310,"push_round_Float"},{0x311,"should_and_did_push_approx_arg2"},
    {0x312,"signum_Float"},{0x313,"did_push_to_polar"},{0x314,"push_degrees"},{0x315,"push_format"},
    {0x316,"push_getkey"},{0x317,"push_getfold"},{0x318,"push_getmode"},{0x319,"push_gettype"},
    {0x31a,"push_instring"},{0x31b,"push_mrow_aux"},{0x31c,"push_part"},{0x31d,"push_pttest"},
    {0x31e,"push_pxltest"},{0x31f,"push_rand"},{0x320,"push_randpoly"},{0x321,"push_setfold"},
    {0x322,"push_setgraph"},{0x323,"push_setmode"},{0x324,"push_settable"},{0x325,"push_str_to_expr"},
    {0x326,"push_string"},{0x327,"push_switch"},{0x328,"psuh_to_cylin"},{0x329,"push_to_sphere"},
    {0x32a,"cmd_andpic"},{0x32b,"cmd_blddata"},{0x32c,"cmd_circle"},{0x32d,"cmd_clrdraw"},
    {0x32e,"cmd_clrerr"},{0x32f,"cmd_clrgraph"},{0x330,"cmd_clrhome"},{0x331,"cmd_clrio"},
    {0x332,"cmd_clrtable"},{0x333,"cmd_copyvar"},{0x334,"cmd_cubicreg"},{0x335,"cmd_custmoff"},
    {0x336,"cmd_custmon"},{0x337,"cmd_custom"},{0x338,"cmd_cycle"},{0x339,"cmd_cyclepic"},
    {0x33a,"cmd_delfold"},{0x33b,"cmd_delvar"},{0x33c,"cmd_dialog"},{0x33d,"cmd_disp"},
    {0x33e,"cmd_dispg"},{0x33f,"cmd_disphome"},{0x340,"cmd_disptbl"},{0x341,"cmd_drawfunc"},
    {0x342,"cmd_drawinv"},{0x343,"cmd_drawparm"},{0x344,"cmd_drawpol"},{0x345,"cmd_else"},
    {0x346,"cmd_endfor"},{0x347,"cmd_endloop"},{0x348,"cmd_endtry"},{0x349,"cmd_endwhile"},
    {0x34a,"cmd_exit"},{0x34b,"cmd_expreg"},{0x34c,"cmd_fill"},{0x34d,"cmd_fnoff"},
    {0x34e,"cmd_fnon"},{0x34f,"cmd_for"},{0x350,"cmd_get"},{0x351,"cmd_getcalc"},
    {0x352,"cmd_goto"},{0x353,"cmd_graph"},{0x354,"cmd_if"},{0x355,"cmd_ifthen"},
    {0x356,"cmd_input"},{0x357,"cmd_inputstr"},{0x358,"cmd_line"},{0x359,"cmd_linehorz"},
    {0x35a,"cmd_linetan"},{0x35b,"cmd_linevert"},{0x35c,"cmd_linreg"},{0x35d,"cm_lnreg"},
    {0x35e,"cmd_local"},{0x35f,"cmd_lock"},{0x360,"cmd_logistic"},{0x361,"cmd_medmed"},
    {0x362,"cmd_movevar"},{0x363,"cmd_newdata"},{0x364,"cmd_newfold"},{0x365,"cmd_newpic"},
    {0x366,"cmd_newplot"},{0x367,"cmd_newprob"},{0x368,"cmd_onevar"},{0x369,"cmd_output"},
    {0x36a,"cmd_passerr"},{0x36b,"cmd_pause"},{0x36c,"cmd_plotsoff"},{0x36d,"cmd_plotson"},
    {0x36e,"cmd_popup"},{0x36f,"cmd_powerreg"},{0x370,"cmd_printobj"},{0x371,"cmd_prompt"},
    {0x372,"cmd_ptchg"},{0x373,"cmd_ptoff"},{0x374,"cmd_pton"},{0x375,"cmd_pttext"},
    {0x376,"cmd_pxlchg"},{0x377,"cmd_cmd_pxlcircle"},{0x378,"cmd_pxlhorz"},{0x379,"cmd_pxlline"},
    {0x37a,"cmd_pxloff"},{0x37b,"cmd_pxlon"},{0x37c,"cmd_pxltext"},{0x37d,"cmd_pxlvert"},
    {0x37e,"cmd_quadreg"},{0x37f,"cmd_quartreg"},{0x380,"cmd_randseed"},{0x381,"cmd_rclgdb"},
    {0x382,"cmd_rclpic"},{0x383,"cmd_rename"},{0x384,"cmd_request"},{0x385,"cmd_return"},
    {0x386,"cmd_rplcpic"},{0x387,"cmd_send"},{0x388,"cmd_sendcalc"},{0x389,"cmd_sendchat"},
    {0x38a,"cmd_shade"},{0x38b,"cmd_showstat"},{0x38c,"cmd_sinreg"},{0x38d,"cmd_slpline"},
    {0x38e,"cmd_sorta"},{0x38f,"cmd_sortd"},{0x390,"cmd_stogdb"},{0x391,"cmd_stopic"},
    {0x392,"cmd_style"},{0x393,"cmd_table"},{0x394,"cmd_text"},{0x395,"cmd_toolbar"},
    {0x396,"cmd_trace"},{0x397,"cmd_try"},{0x398,"cmd_twovar"},{0x399,"cmd_unlock"},
    {0x39a,"cmd_while"},{0x39b,"cmd_xorpic"},{0x39c,"cmd_zoombox"},{0x39d,"cmd_zoomdata"},
    {0x39e,"cmd_zoomdec"},{0x39f,"cmd_zoomfit"},{0x3a0,"cmd_zoomin"},{0x3a1,"cmd_zoomint"},
    {0x3a2,"cmd_zoomout"},{0x3a3,"cmd_zoomprev"},{0x3a4,"cmd_zoomrcl"},{0x3a5,"cmd_zoomsqr"},
    {0x3a6,"cmd_zoomstd"},{0x3a7,"cmd_zoomsto"},{0x3a8,"cmd_zoomtrig"},{0x3a9,"OSenqueue"},
    {0x3aa,"OSdequeue"},{0x3ab,"OSqinquire"},{0x3ac,"OSqhead"},{0x3ad,"OSqclear"},
    {0x3ae,"did_push_divide_units"},{0x3af,"has_unit_base"},{0x3b0,"init_unit_system"},{0x3b1,"is_units_term"},
    {0x3b2,"push_auto_units_conversion"},{0x3b3,"push_unit_system_list"},
    {0x3b4,"setup_unit_system"},{0x3b5,"all_tail"},{0x3b6,"any_tail"},{0x3b7,"is_matrix"},{0x3b8,"is_square_matrix"},
    {0x3b9,"is_valid_smap_aggregate"},{0x3ba,"last_element_index"},{0x3bb,"map_tail"},{0x3bc,"map_tail_Int"},
    {0x3bd,"push_list_plus"},{0x3be,"push_list_times"},{0x3bf,"push_reversed_tail"},
    {0x3c0,"push_sq_matrix_to_whole_number"},{0x3c1,"push_transpose_aux"},{0x3c2,"push_zero_partial_column"},
    {0x3c3,"remaining_element_count"},{0x3c4,"push_offset_array"},{0x3c5,"push_matrix_product"},
    {0x3c6,"is_pathname"},{0x3c7,"next_token"},{0x3c8,"nonblank"},{0x3c9,"push_parse_prgm_or_func_text"},
    {0x3ca,"push_parse_text"},{0,NULL}};


static char *ccodes[16] = { "t ", "f ", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" };
static int  pc;


#define PARAM_WORD(v) ((v) = (unsigned short)((p[0] << 8) + p[1]), p += 2)
#define PARAM_LONG(v) ((v) = (((unsigned int)((p[0] << 8) + p[1])) << 16) + (unsigned int)((p[2] << 8) + p[3]), p += 4)


#define GET_WORD(m)   ((unsigned short)((((m)[0]) << 8) + ((m)[1])))
#define GET_DWORD(m)  (((unsigned int)(((m)[0] << 8) + (m)[1])) << 16) + ((unsigned int)(((m)[2] << 8) + (m)[3])))


static char tmpStr[64];
int         romFuncAddr[0x800];





long* label_list       = NULL;
int   label_count      = 0;
int   labels_allocated = 0;

#define LABEL_ALLOC_STEP 10

//=============================================================================
// adds a label to the list
//=============================================================================
int AddLabel(long address) {
    int i = -1;

    if (label_count != 0) {
        for (i=0;i<label_count;i++) if (label_list[i] == address) return 1;
    }

    if (label_count == labels_allocated) {
        int* tmp = (long*)realloc(label_list,(labels_allocated+LABEL_ALLOC_STEP)*sizeof(long));
        if (!tmp) {
            label_parse = 0;
            return 0;
        }
        label_list = tmp;
        labels_allocated+=LABEL_ALLOC_STEP;
    }
    label_list[label_count++] = address;
    return 1;
}


//=============================================================================
// adds a label to the list
//=============================================================================
char label_name[200];
char* GetLabel(long address) {
    int i = -1;

    if (no_labels) return NULL;

    if (label_count != 0) {
        for (i=0;i<label_count;i++) if (label_list[i] == address) break;
    }
    if (i != label_count && i != -1) {
        sprintf(label_name,"__L%lX",label_list[i]);
        return label_name;
    }
    return NULL;
}


//=============================================================================
// some helper functions
//=============================================================================
int getmem(int addr) {
    addr&=0xffffff;
    if (addr<0x600000) return (mem[addr>>16][addr&0xffff] & 0xff);
    return 0x00;
}

int getmem_word(int addr) {
    return ((getmem(addr)<<8)|getmem(addr+1))&0xffff;
}

int getmem_dword(int addr) {
    return (getmem(addr)<<24)|
           (getmem(addr+1)<<16)|
           (getmem(addr+2)<<8)|
            getmem(addr+3);
}

#define ROMFLAG_TI89      1
#define ROMFLAG_INTERNAL  2
#define ROMFLAG_UPDATE    4
#define ROMFLAG_FLASHROM  8
#define ROMFLAG_SPECIAL  16

void PrintROMFlags(int flags) {
    if (flags & ROMFLAG_TI89)     printf("TI89 ");
    if (flags & ROMFLAG_INTERNAL) printf("INTERNAL ");
    if (flags & ROMFLAG_UPDATE)   printf("UPDATE ");
    if (flags & ROMFLAG_FLASHROM) printf("FLASHROM ");
    if (flags & ROMFLAG_SPECIAL)  printf("SPECIAL ");
}

int IsNum(char c) {
    if ( c>='0' && c<='9') return 1;
    return 0;
}

int IsAlNum(char c) {
    if (c>='0' && c<='9') return 1;
    if (c>='a' && c<='z') return 1;
    if (c>='A' && c<='Z') return 1;
    if (c==' ')           return 1;
    return 0;
}

int read_dword(unsigned char* ptr) {
    return (ptr[0]<<24)|(ptr[1]<<16)|(ptr[2]<<8)|ptr[3];
}


//=============================================================================
// open and check *.rom files
//=============================================================================
unsigned char* OpenROM(char* name,int* size,int* flags) {
    FILE*          fp;
    unsigned char* buf;
    int            ver = 0;
    int            i;

    *flags = 0;

    if (!(fp=fopen(name,"rb"))) {
        fprintf(stderr,"ERROR: cannot open ROM %s\n",name);
        return 0;
    }

    fseek(fp,0,SEEK_END);
    *size = ftell(fp);
    rewind(fp);

    if (*size != 1024*1024 && *size != 2048*1024) {
        fprintf(stderr,"ERROR: invalid size for ROM %s (%d)\n",name,*size);
        fclose(fp);
        return 0;
    }


    if (!(buf = malloc(*size))) {
        fprintf(stderr,"ERROR: cannot allocate %d bytes\n",*size);
        fclose(fp);
        return 0;
    }

    fread(buf,1,*size,fp);
    fclose(fp);

    if ((buf[5]&0x60)==0x20) *flags |= ROMFLAG_INTERNAL;
    if (!(buf[0x65]&0xf))    *flags |= ROMFLAG_FLASHROM;

    if ((*flags&ROMFLAG_INTERNAL) && (*flags&ROMFLAG_FLASHROM)) *flags|=ROMFLAG_TI89;

    for (i=0;i<*size-16;i+=2) {
        if (IsNum(buf[i])      && (buf[i+1]=='.')   && IsNum(buf[i+2])    &&
            (buf[i+3]==0)      && IsAlNum(buf[i+4]) && IsAlNum(buf[i+5])  &&
            IsAlNum(buf[i+7])  && IsAlNum(buf[i+8]) && IsAlNum(buf[i+10]) &&
            IsAlNum(buf[i+11]))
        {
            ver=i;
            break;
        }
        if (IsNum(buf[i])      && (buf[i+1]=='.')    && IsNum(buf[i+2])   &&
            IsNum(buf[i+3])    && (buf[i+4]==0)      && IsAlNum(buf[i+5]) &&
            IsAlNum(buf[i+6])  && IsAlNum(buf[i+8])  && IsAlNum(buf[i+9]) &&
            IsAlNum(buf[i+11]) && IsAlNum(buf[i+12]))
        {
            ver=i;
            break;
        }
    }

    if (!ver) {
        fprintf(stderr,"ERROR: version of ROM %s not found\n",name);
        free(buf);
        return 0;
    }


    if (*flags&ROMFLAG_TI89) {
        printf("/*[ROM TI-89 version %s]*/\n",&buf[ver]);
    }
    else {
        if (*flags&ROMFLAG_FLASHROM) {
            printf("/*[ROM TI-92 Plus version %s]*/\n",&buf[ver]);
        }
        else {
            if (*flags&ROMFLAG_INTERNAL) printf("/*[ROM TI-92 version %s (internal)]*/\n",&buf[ver]);
            else                         printf("/*[ROM TI-92 version %s (external)]*/\n",&buf[ver]);
        }
    }

    return buf;
}


//=============================================================================
// open and check *.tib files
//=============================================================================
unsigned char* OpenROMUpdate(char *name,int* size,int* flags) {
    FILE*          fp;
    unsigned char* buf;
    int            ver = 0;
    int            i;

    if (!(fp=fopen(name,"rb"))) {
        fprintf(stderr,"ERROR: cannot open ROM-Update %s\n",name);
        return 0;
    }

    fseek(fp,0,SEEK_END);
    *size = ftell(fp);
    rewind(fp);

    if (!(buf = malloc(*size))) {
        fprintf(stderr,"ERROR: cannot allocate %d bytes\n",*size);
        fclose(fp);
        return 0;
    }

    fread(buf,1,*size,fp);
    fclose(fp);

    *flags=ROMFLAG_UPDATE|ROMFLAG_FLASHROM;

    if ((buf[0x8d]&0x60)==0x20) *flags|=ROMFLAG_INTERNAL|ROMFLAG_TI89;

    if (!strncmp(&buf[0x16],"Advanced Mathematics Software",29)) {
       for (i=0;i<*size-16;i+=2) {
            if (IsNum(buf[i])      && (buf[i+1]=='.')   && IsNum(buf[i+2])    &&
                (buf[i+3]==0)      && IsAlNum(buf[i+4]) && IsAlNum(buf[i+5])  &&
                IsAlNum(buf[i+7])  && IsAlNum(buf[i+8]) && IsAlNum(buf[i+10]) &&
                IsAlNum(buf[i+11]))
            {
                ver=i;
                break;
            }
            if (IsNum(buf[i])     && (buf[i+1]=='.')   && IsNum(buf[i+2])   &&
                IsNum(buf[i+3])   && (buf[i+4]==0)     && IsAlNum(buf[i+5]) &&
                IsAlNum(buf[i+6]) && IsAlNum(buf[i+8]) && IsAlNum(buf[i+9]) &&
                IsAlNum(buf[i+11])&& IsAlNum(buf[i+12]))
            {
                ver=i;
                break;
            }
        }
    }

    if (!ver) {
        fprintf(stderr,"ERROR: version of ROM-Update %s not found\n",name);
        free(buf);
        return 0;
    }

    if (*flags&ROMFLAG_TI89) printf("/*[ROM-Update TI-89 version %s (update)]*/\n",&buf[ver]);
    else                     printf("/*[ROM-Update TI-92 Plus version %s (update)]*/\n",&buf[ver]);


    return buf;
}


//=============================================================================
// frees buffers used for ROM
//=============================================================================
void CleanupROM() {
   if (rom) free(rom);
   if (ram) free(ram);
   rom = 0;
}


//=============================================================================
// load a ROM file
//=============================================================================
int LoadROM(char* filename) {
    unsigned char* buf;
    int            flen = strlen(filename);
    int            flags;
    int            size;
    int            i;

    rom  = (unsigned char*)malloc(2048*1024+3);
    ram  = (unsigned char*)malloc(256*1024+3);

    if (!rom || !ram) {
        CleanupROM();
            fprintf(stderr,"ERROR: cannot allocate memory for ROM\n");
        return 0;
    }

        for (i=0;i<2048*1024;i++) {
                if (i&1) rom[i]=0;
                else     rom[i]=0x14;
        }


        if (flen < 5) {
            fprintf(stderr,"ERROR: invalid ROM filename %s\n",filename);
            CleanupROM();
        return 0;
        }

    if (!strncmp(".ROM",filename+flen-4,4) || !strncmp(".rom",filename+flen-4,4)) {
        buf = OpenROM(filename,&size,&flags);
        if (buf) printf("/*[ ");PrintROMFlags(flags);printf("]*/\n");
        }
    else if (!strncmp(".TIB",filename+flen-4,4) || !strncmp(".tib",filename+flen-4,4)) {
        buf = OpenROMUpdate(filename,&size,&flags);
        if (buf) printf("/*[ ");PrintROMFlags(flags);printf("]*/\n");
        }
        else {
            fprintf(stderr,"ERROR: invalid ROM filename %s (neither .ROM nor .TIB)\n",filename);
            CleanupROM();
        return 0;
        }

    memcpy(rom,buf,size);
    if (size<(2048*1024)) {
        int i;
        for (i=0;i<0x100000;i++) rom[i+0x100000]=rom[i];
    }

    if (flags & ROMFLAG_FLASHROM) {
        initialPC     = read_dword(&rom[0x1208c]);
        initIntTabOfs = 0x12088;
    }
    else {
        initialPC     = read_dword(&rom[4]);
        initIntTabOfs = 0;
    }

    free(buf);

    printf("/*[initialPC     = 0x%x (%d)]*/\n",initialPC,initialPC);
    printf("/*[initIntTabOfs = 0x%x (%d)]*/\n\n",initIntTabOfs,initIntTabOfs);

    return 1;
}


//=============================================================================
// initialize memory pointers
//=============================================================================
void InitMemoryPointers() {
    int i;
    for (i=0;i<0x40000;i++) ram[i]=0;
    for (i=0;i<256;i++)     ram[i]=rom[i+initIntTabOfs];
    for (i=0;i<32;i++)      mem[i]=&ram[(i&3)<<16];
    for (i=0;i<32;i++)      mem[i+32]=&rom[i<<16];
    for (i=0;i<32;i++)      mem[i+64]=&rom[i<<16];
    for (i=96;i<256;i++)    mem[i]=garbagemem;
    for (i=0;i<0x10000;i++) garbagemem[i]=0x14;
}


//=============================================================================
// initialized ROM function table
//=============================================================================
void InitializeROMFuncs(int rom_given) {
    int i;
    memset(romFuncAddr,0,sizeof(int)*0x800);

    if (rom_given) {
        for (i=0;(romFuncs[i].name)&&(i<(getmem_dword(getmem_dword(0xc8)-4))-1);i++)
            romFuncAddr[i]=getmem_dword(getmem_dword(0xc8)+(i<<2));
    }
}


//=============================================================================
// helper function for disassembling engine
//=============================================================================
char* Offset2Name(int addr) {
    int i;
    for (i=0;(romFuncs[i].name);i++) {
        if (addr == romFuncs[i].num*4) return romFuncs[i].name;
    }
    return 0;
}


//=============================================================================
// helper function for disassembling engine
//=============================================================================
int IsROMAddr(int addr) {
    int i;
    if (addr==0) return 0;
    if (!romFuncs) return 0;
    for (i=0;romFuncs[i].name;i++) {
        if (addr==romFuncAddr[i]) return 1;
    }
    return 0;
}


//=============================================================================
// helper function for disassembling engine
//=============================================================================
char* ROMAddrName(int addr) {
    int i;
    for (i=0;romFuncs[i].name;i++) {
        if (addr==romFuncAddr[i]) {
            sprintf(tmpStr,"tios::%s",romFuncs[i].name);
            return tmpStr;
        }
    }
    return "Internal Error";
}


static char* offsetname_ptr;

//=============================================================================
// helper function for disassembling engine
//=============================================================================
static char* MakeEA(int lo, unsigned char* pBase, int size, int* count) {
    static char    buffer[2][80];
    static int     which;
    unsigned char* p   = pBase;
    char*          buf = buffer[which];
    int            reg = lo & 7;
    unsigned long  pm;
    int            temp;

    which ^= 1;
    switch ((lo >> 3) & 7) {
        case 0: sprintf(buf, "%%d%d", reg);    break;
        case 1: sprintf(buf, "%%a%d", reg);    break;
        case 2: sprintf(buf, "(%%a%d)", reg);  break;
        case 3: sprintf(buf, "(%%a%d)+", reg); break;
        case 4: sprintf(buf, "-(%%a%d)", reg); break;
        case 5: PARAM_WORD(pm);
                if (pm & 0x8000) sprintf(buf, "(-0x%X,%%a%d)", -(signed short)pm & 0xffff, reg);
                else {
                    offsetname_ptr = Offset2Name(pm);
                    sprintf(buf, "(0x%lX,%%a%d)", pm, reg);
                }
                break;
        case 6: PARAM_WORD(pm);
                temp = pm & 0xff;
                if (temp & 0x80) sprintf(buf, "(-0x%X,%%a%d,%%d%ld.%c)", -(signed char)temp & 0xff, reg, (pm >> 12) & 7, (pm & 800) ? 'l' : 'w');
                else             sprintf(buf, "(0x%X,%%a%d,%%d%ld.%c)", temp, reg, (pm >> 12) & 7, (pm & 800) ? 'l' : 'w');
                break;
        case 7: switch (reg) {
                    case 0: PARAM_WORD(pm);
                            sprintf(buf, "0x%lX", pm);
                            break;
                    case 1: PARAM_LONG(pm);
                            if (IsROMAddr(pm)) strcpy(buf,ROMAddrName(pm));
                            else               sprintf(buf, "0x%lX", pm);
                            break;
                    case 2: PARAM_WORD(pm);

                            //if (IsROMAddr(pc + (signed short)pm + 2)) sprintf(buf, "%s",ROMAddrName(pc + (signed short)pm + 2));
                            if (pm & 0x8000) {
                                if (label_parse) {
                                    AddLabel(pc + (signed short)pm + 2);
                                }
                                else {
                                    char* s = GetLabel(pc + (signed short)pm + 2);
                                    if (!s) {
                                        sprintf(buf, "(-0x%X,%%pc)", -(signed short)pm & 0xffff);
                                    }
                                    else {
                                        sprintf(buf, "(%s,%%pc)",s);
                                    }
                                }
                            }
                            else {
                                if (label_parse) {
                                    AddLabel(pc + (signed short)pm + 2);
                                }
                                else {
                                    char* s = GetLabel(pc + (signed short)pm + 2);
                                    if (!s) {
                                        sprintf(buf, "(0x%lX,%%pc)", pm);
                                    }
                                    else {
                                        sprintf(buf, "(%s,%%pc)", s);
                                    }
                                }
                            }
                            break;
                    case 3: PARAM_WORD(pm);
                            temp = pm & 0xff;
                            if (temp & 0x80) {
                                if (label_parse) {
                                    AddLabel(pc +(signed char)temp+2);
                                }
                                else {
                                    char* s = GetLabel(pc +(signed char)temp+2);
                                    if (!s) {
                                        sprintf(buf, "(-0x%X,%%pc,%%d%ld.%c)",
                                            -(signed char)temp & 0xff,
                                            (pm >> 12) & 7,
                                            (pm & 800) ? 'l' : 'w');
                                    }
                                    else {
                                        sprintf(buf, "(%s,%%pc,%%d%ld.%c)",
                                                s,
                                                (pm >> 12) & 7,
                                                (pm & 800) ? 'l' : 'w');
                                    }
                                }
                            }
                            else {
                                if (label_parse) {
                                    AddLabel(pc+temp+2);
                                }
                                else {
                                    char* s = GetLabel(pc+temp+2);
                                    if (!s) {
                                        sprintf(buf, "(0x%X,%%pc,%%d%ld.%c)",
                                            temp, (pm >> 12) & 7,
                                            (pm & 800) ? 'l' : 'w');
                                    }
                                    else {
                                        sprintf(buf, "(%s,%%pc,%%d%ld.%c)",
                                                s, (pm >> 12) & 7,
                                                (pm & 800) ? 'l' : 'w');
                                    }
                                }
                            }
                            break;
                    case 4: if (size == 1) {
                                PARAM_WORD(pm);
                                temp = pm & 0xff;
                                sprintf(buf, "#0x%X", temp);
                            }
                            else if (size == 2) {
                                PARAM_WORD(pm);
                                sprintf(buf, "#0x%lX", pm);
                            }
                            else {
                                PARAM_LONG(pm);
                                sprintf(buf, "#0x%lX", pm);
                            }
                            break;
                }
                break;
    }

    *count = p - pBase;
    return buf;
}


//=============================================================================
// helper function for disassembling engine
//=============================================================================
static char* MakeRegList(char* p, unsigned short pm) {
    int start = -1, sep = 0;
    int i;

    for (i=0; i<8; i++, pm>>=1) {
        if ((pm & 1) && start == -1)
            start = i;
        else if (!(pm & 1) && start != -1) {
            if (sep++)          p += sprintf(p, "/");
            if (start == i - 1) p += sprintf(p, "%%d%d", start);
            else                p += sprintf(p, "%%d%d-%%d%d", start, i - 1);
            start = -1;
        }
    }
    if (start != -1) {
        if (sep++)      p += sprintf(p, "/");
        if (start == 7) p += sprintf(p, "%%d7");
        else            p += sprintf(p, "%%d%d-%%d7", start);
        start = -1;
    }

    for (i=0; i<8; i++, pm>>=1) {
        if ((pm & 1) && start == -1)
            start = i;
        else if (!(pm & 1) && start != -1) {
            if (sep++)          p += sprintf(p, "/");
            if (start == i - 1) p += sprintf(p, "%%a%d", start);
            else                p += sprintf(p, "%%a%d-%%a%d", start, i - 1);
            start = -1;
        }
    }
    if (start != -1) {
        if (sep++)      p += sprintf(p, "/");
        if (start == 7) p += sprintf(p, "%%a7");
        else            p += sprintf(p, "%%a%d-%%a7", start);
    }

    return p;
}


//=============================================================================
// helper function for disassembling engine
//=============================================================================
static char* MakeRevRegList(char* p, unsigned short pm) {
    int start = -1, sep = 0;
    int i;

    for (i=0; i<8; i++, pm<<=1) {
        if ((pm & 0x8000) && start == -1)
            start = i;
        else if (!(pm & 0x8000) && start != -1) {
            if (sep++)          p += sprintf(p, "/");
            if (start == i - 1) p += sprintf(p, "%%d%d", start);
            else                p += sprintf(p, "%%d%d-%%d%d", start, i - 1);
            start = -1;
        }
    }
    if (start != -1) {
        if (sep++)      p += sprintf(p, "/");
        if (start == 7) p += sprintf(p, "%%d7");
        else            p += sprintf(p, "%%d%d-%%d7", start);
        start = -1;
    }

    for (i=0; i<8; i++, pm<<=1) {
        if ((pm & 0x8000) && start == -1)
            start = i;
        else if (!(pm & 0x8000) && start != -1) {
            if (sep++)          p += sprintf(p, "/");
            if (start == i - 1) p += sprintf(p, "%%a%d", start);
            else                p += sprintf(p, "%%a%d-%%a%d", start, i - 1);
            start = -1;
        }
    }
    if (start != -1) {
        if (sep++)      p += sprintf(p, "/");
        if (start == 7) p += sprintf(p, "%%a7");
        else            p += sprintf(p, "%%a%d-%%a7", start);
    }

    return p;
}


//=============================================================================
// the disassembling engine
//=============================================================================
int Dasm68000(unsigned char* pBase, char* buffer, int _pc) {
    unsigned char* ea;
    unsigned char* ea2;
    unsigned char* p = pBase;
    unsigned short op;
    unsigned short lo;
    unsigned short rhi;
    unsigned short rlo;
    unsigned long  pm;
    int            count;

    pc=_pc;

    offsetname_ptr = 0;

    PARAM_WORD(op);

    lo  = op & 0x3f;
    rhi = (op >> 9) & 7;
    rlo = op & 7;

    switch (op & 0xffc0) {
        case 0x0000:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "ori      #0x%lX,%%ccr", pm & 0xff);
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "ori.b    #0x%lX,%s", pm & 0xff, ea);
            }
            break;
        case 0x0040:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "ori      #0x%lX,%%sr", pm & 0xffff);
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "ori.w    #0x%lX,%s", pm & 0xffff, ea);
            }
            break;
        case 0x0080:
            PARAM_LONG(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "ori.l    #0x%lX,%s", pm, ea);
            break;
        case 0x0100: case 0x0300: case 0x0500:
        case 0x0700: case 0x0900: case 0x0b00:
        case 0x0d00: case 0x0f00:
            if ((lo & 0x38) == 0x08) {
                PARAM_WORD(pm);
                sprintf(buffer, "movep.w  (0x%lX,%%a%d),%%d%d", pm, rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "btst     %%d%d,%s", rhi, ea);
            }
            break;
        case 0x0140: case 0x0340: case 0x0540:
        case 0x0740: case 0x0940: case 0x0b40:
        case 0x0d40: case 0x0f40:
            if ((lo & 0x38) == 0x08) {
                PARAM_WORD(pm);
                sprintf(buffer, "movep.l  (0x%lX,%%a%d),%%d%d", pm, rlo, rhi);
            }
            else {
                ea = MakeEA (lo, p, 2, &count); p += count;
                sprintf(buffer, "bchg     %%d%d,%s", rhi, ea);
            }
            break;
        case 0x0180: case 0x0380: case 0x0580:
        case 0x0780: case 0x0980: case 0x0b80:
        case 0x0d80: case 0x0f80:
            if ((lo & 0x38) == 0x08) {
                PARAM_WORD(pm);
                sprintf(buffer, "movep.w  %%d%d,(0x%lX,%%a%d)", rhi, pm, rlo);
            }
            else {
                ea = MakeEA (lo, p, 2, &count);
                p += count;
                sprintf(buffer, "bclr     %%d%d,%s", rhi, ea);
            }
            break;
        case 0x01c0: case 0x03c0: case 0x05c0:
        case 0x07c0: case 0x09c0: case 0x0bc0:
        case 0x0dc0: case 0x0fc0:
            if ((lo & 0x38) == 0x08) {
                PARAM_WORD(pm);
                sprintf(buffer, "movep.l  %%d%d,(0x%lX,%%a%d)", rhi, pm, rlo);
            }
            else {
                ea = MakeEA (lo, p, 2, &count);
                p += count;
                sprintf(buffer, "bset     %%d%d,%s", rhi, ea);
            }
            break;
        case 0x0200:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "andi     #0x%lX,%%ccr", pm & 0xff);
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "andi.b   #0x%lX,%s", pm & 0xff, ea);
            }
            break;
        case 0x0240:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "andi     #0x%lX,%%sr", pm & 0xffff);
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "andi.w   #0x%lX,%s", pm & 0xffff, ea);
            }
            break;
        case 0x0280:
            PARAM_LONG(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "andi.l   #0x%lX,%s", pm, ea);
            break;
        case 0x0400:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "subi.b   #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0440:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "subi.w   #0x%lX,%s", pm & 0xffff, ea);
            break;
        case 0x0480:
            PARAM_LONG(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "subi.l   #0x%lX,%s", pm, ea);
            break;
        case 0x0600:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "addi.b   #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0640:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "addi.w   #0x%lX,%s", pm & 0xffff, ea);
            break;
        case 0x0680:
            PARAM_LONG(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "addi.l   #0x%lX,%s", pm, ea);
            break;
        case 0x0800:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "btst     #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0840:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "bchg     #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0880:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "bclr     #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x08c0:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "bset     #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0a00:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "eori     #0x%lX,%%ccr", pm & 0xff);
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "eori.b   #0x%lX,%s", pm & 0xff, ea);
            }
            break;
        case 0x0a40:
            PARAM_WORD(pm);
            if (lo == 0x3c) sprintf(buffer, "eori     #0x%lX,%%sr", pm & 0xffff);
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "eori.w   #0x%lX,%s", pm & 0xffff, ea);
            }
            break;
        case 0x0a80:
            PARAM_LONG(pm);
            ea = MakeEA (lo, p, 4, &count);
            p += count;
            sprintf(buffer, "eori.l   #0x%lX,%s", pm, ea);
            break;
        case 0x0c00:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "cmpi.b   #0x%lX,%s", pm & 0xff, ea);
            break;
        case 0x0c40:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "cmpi.w   #0x%lX,%s", pm & 0xffff, ea);
            break;
        case 0x0c80:
            PARAM_LONG(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "cmpi.l   #0x%lX,%s", pm, ea);
            break;
        case 0x0e00:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            if (pm & 0x0800) {
                if (pm & 0x8000) sprintf(buffer, "moves.b  %%a%ld,%s", (pm >> 12) & 7, ea);
                else             sprintf(buffer, "moves.b  %%d%ld,%s", (pm >> 12) & 7, ea);
            }
            else {
                if (pm & 0x8000) sprintf(buffer, "moves.b  %s,%%a%ld", ea, (pm >> 12) & 7);
                else             sprintf(buffer, "moves.b  %s,%%d%ld", ea, (pm >> 12) & 7);
            }
            break;
        case 0x0e40:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            if (pm & 0x0800) {
                if (pm & 0x8000) sprintf(buffer, "moves.w  %%a%ld,%s", (pm >> 12) & 7, ea);
                else             sprintf(buffer, "moves.w  %%d%ld,%s", (pm >> 12) & 7, ea);
            }
            else {
                if (pm & 0x8000) sprintf(buffer, "moves.w  %s,%%a%ld", ea, (pm >> 12) & 7);
                else             sprintf(buffer, "moves.w  %s,%%d%ld", ea, (pm >> 12) & 7);
            }
            break;
        case 0x0e80:
            PARAM_WORD(pm);
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            if (pm & 0x0800) {
                if (pm & 0x8000) sprintf(buffer, "moves.l  %%a%ld,%s", (pm >> 12) & 7, ea);
                else             sprintf(buffer, "moves.l  %%d%ld,%s", (pm >> 12) & 7, ea);
            }
            else {
                if (pm & 0x8000) sprintf(buffer, "moves.l  %s,%%a%ld", ea, (pm >> 12) & 7);
                else             sprintf(buffer, "moves.l  %s,%%d%ld", ea, (pm >> 12) & 7);
            }
            break;
        case 0x1000: case 0x1080: case 0x10c0:
        case 0x1100: case 0x1140: case 0x1180:
        case 0x11c0: case 0x1200: case 0x1280:
        case 0x12c0: case 0x1300: case 0x1340:
        case 0x1380: case 0x13c0: case 0x1400:
        case 0x1480: case 0x14c0: case 0x1500:
        case 0x1540: case 0x1580: case 0x1600:
        case 0x1680: case 0x16c0: case 0x1700:
        case 0x1740: case 0x1780: case 0x1800:
        case 0x1880: case 0x18c0: case 0x1900:
        case 0x1940: case 0x1980: case 0x1a00:
        case 0x1a80: case 0x1ac0: case 0x1b00:
        case 0x1b40: case 0x1b80: case 0x1c00:
        case 0x1c80: case 0x1cc0: case 0x1d00:
        case 0x1d40: case 0x1d80: case 0x1e00:
        case 0x1e80: case 0x1ec0: case 0x1f00:
        case 0x1f40: case 0x1f80:
            ea  = MakeEA(lo, p, 1, &count);
            p  += count;
            ea2 = MakeEA(((op >> 9) & 0x07) + ((op >> 3) & 0x38), p, 1, &count);
            p  += count;
            sprintf(buffer, "move.b   %s,%s", ea, ea2);
            break;
        case 0x2000: case 0x2080: case 0x20c0:
        case 0x2100: case 0x2140: case 0x2180:
        case 0x21c0: case 0x2200: case 0x2280:
        case 0x22c0: case 0x2300: case 0x2340:
        case 0x2380: case 0x23c0: case 0x2400:
        case 0x2480: case 0x24c0: case 0x2500:
        case 0x2540: case 0x2580: case 0x2600:
        case 0x2680: case 0x26c0: case 0x2700:
        case 0x2740: case 0x2780: case 0x2800:
        case 0x2880: case 0x28c0: case 0x2900:
        case 0x2940: case 0x2980: case 0x2a00:
        case 0x2a80: case 0x2ac0: case 0x2b00:
        case 0x2b40: case 0x2b80: case 0x2c00:
        case 0x2c80: case 0x2cc0: case 0x2d00:
        case 0x2d40: case 0x2d80: case 0x2e00:
        case 0x2e80: case 0x2ec0: case 0x2f00:
        case 0x2f40: case 0x2f80:
            ea  = MakeEA(lo, p, 4, &count);
            p  += count;
            ea2 = MakeEA(((op >> 9) & 0x07) + ((op >> 3) & 0x38), p, 4, &count);
            p  += count;
            sprintf(buffer, "move.l   %s,%s", ea, ea2);
            break;
        case 0x2040: case 0x2240: case 0x2440:
        case 0x2640: case 0x2840: case 0x2a40:
        case 0x2c40: case 0x2e40:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "movea.l  %s,%%a%d", ea, rhi);
            break;
        case 0x3000: case 0x3080: case 0x30c0:
        case 0x3100: case 0x3140: case 0x3180:
        case 0x31c0: case 0x3200: case 0x3280:
        case 0x32c0: case 0x3300: case 0x3340:
        case 0x3380: case 0x33c0: case 0x3400:
        case 0x3480: case 0x34c0: case 0x3500:
        case 0x3540: case 0x3580: case 0x3600:
        case 0x3680: case 0x36c0: case 0x3700:
        case 0x3740: case 0x3780: case 0x3800:
        case 0x3880: case 0x38c0: case 0x3900:
        case 0x3940: case 0x3980: case 0x3a00:
        case 0x3a80: case 0x3ac0: case 0x3b00:
        case 0x3b40: case 0x3b80: case 0x3c00:
        case 0x3c80: case 0x3cc0: case 0x3d00:
        case 0x3d40: case 0x3d80: case 0x3e00:
        case 0x3e80: case 0x3ec0: case 0x3f00:
        case 0x3f40: case 0x3f80:
            ea  = MakeEA(lo, p, 2, &count);
            p  += count;
            ea2 = MakeEA(((op >> 9) & 0x07) + ((op >> 3) & 0x38), p, 2, &count);
            p  += count;
            sprintf(buffer, "move.w   %s,%s", ea, ea2);
            break;
        case 0x3040: case 0x3240: case 0x3440:
        case 0x3640: case 0x3840: case 0x3a40:
        case 0x3c40: case 0x3e40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "movea.w  %s,%%a%d", ea, rhi);
            break;
        case 0x4000:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "negx.b   %s", ea);
            break;
        case 0x4040:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "negx.w   %s", ea);
            break;
        case 0x4080:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "negx.l   %s", ea);
            break;
        case 0x40c0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "move     %%sr,%s", ea);
            break;
        case 0x4180: case 0x4380: case 0x4580:
        case 0x4780: case 0x4980: case 0x4b80:
        case 0x4d80: case 0x4f80:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "chk.w    %s,%%d%d", ea, rhi);
            break;
        case 0x41c0: case 0x43c0: case 0x45c0:
        case 0x47c0: case 0x49c0: case 0x4bc0:
        case 0x4dc0: case 0x4fc0:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "lea      %s,%%a%d", ea, rhi);
            break;
        case 0x4200:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "clr.b    %s", ea);
            break;
        case 0x4240:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "clr.w    %s", ea);
            break;
        case 0x4280:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "clr.l    %s", ea);
            break;
        case 0x42c0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "move     %%ccr,%s", ea);
            break;
        case 0x4400:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "neg.b    %s", ea);
            break;
        case 0x4440:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "neg.w    %s", ea);
            break;
        case 0x4480:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "neg.l    %s", ea);
            break;
        case 0x44c0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "move     %s,%%ccr", ea);
            break;
        case 0x4600:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "not.b    %s", ea);
            break;
        case 0x4640:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "not.w    %s", ea);
            break;
        case 0x4680:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "not.l    %s", ea);
            break;
        case 0x46c0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "move     %s,%%sr", ea);
            break;
        case 0x4800:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "nbcd.b   %s", ea);
            break;
        case 0x4840:
            if ((lo & 0x38) == 0x00) sprintf(buffer, "swap     %%d%d", rlo);
            else {
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                sprintf(buffer, "pea      %s", ea);
            }
            break;
        case 0x4880:
            if ((lo & 0x38) == 0x00) sprintf(buffer, "ext.w    %%d%d", rlo);
            else {
                char *b = buffer;
                PARAM_WORD(pm);
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                b += sprintf(b, "movem.w  ");
                if ((lo & 0x38) != 0x20) b = MakeRegList(b, pm);
                else                     b = MakeRevRegList(b, pm);
                sprintf(b, ",%s", ea);
            }
            break;
        case 0x48c0:
            if ((lo & 0x38) == 0x00) sprintf(buffer, "ext.l    %%d%d", rlo);
            else {
                char *b = buffer;
                PARAM_WORD(pm);
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                b += sprintf(b, "movem.l  ");
                if ((lo & 0x38) != 0x20) b = MakeRegList(b, pm);
                else                     b = MakeRevRegList(b, pm);
                sprintf(b, ",%s", ea);
            }
            break;
        case 0x4a00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "tst.b    %s", ea);
            break;
        case 0x4a40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "tst.w    %s", ea);
            break;
        case 0x4a80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "tst.l    %s", ea);
            break;
        case 0x4ac0:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "tas.b    %s", ea);
            break;
        case 0x4c80:
            {
                char *b = buffer;
                PARAM_WORD(pm);
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                b += sprintf(b, "movem.w  %s,", ea);
                b = MakeRegList(b, pm);
            }
            break;
        case 0x4cc0:
            {
                char *b = buffer;
                PARAM_WORD(pm);
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                b += sprintf(b, "movem.l  %s,", ea);
                b = MakeRegList(b, pm);
            }
            break;
        case 0x4e40:
            if ((lo & 0x30) == 0x00) sprintf(buffer, "trap     #0x%X", lo & 15);
            else if ((lo & 0x38) == 0x10) {
                PARAM_WORD(pm);
                sprintf(buffer, "link     %%a%d,#0x%lX", rlo, pm);
            }
            else if ((lo & 0x38) == 0x18) sprintf(buffer, "unlk     %%a%d", rlo);
            else if ((lo & 0x38) == 0x20) sprintf(buffer, "move     %%a%d,%%usp", rlo);
            else if ((lo & 0x38) == 0x28) sprintf(buffer, "move     %%usp,%%a%d", rlo);
            else if (lo == 0x30)          sprintf(buffer, "reset");
            else if (lo == 0x31)          sprintf(buffer, "nop");
            else if (lo == 0x32)          sprintf(buffer, "stop");
            else if (lo == 0x33)          sprintf(buffer, "rte");
            else if (lo == 0x35)          sprintf(buffer, "rts");
            else if (lo == 0x36)          sprintf(buffer, "trapv");
            else if (lo == 0x37)          sprintf(buffer, "rtr");
            else if (lo == 0x3a) {
                PARAM_WORD(pm);
                switch (pm & 0xfff) {
                    case 0x000: ea = "sfc"; break;
                    case 0x001: ea = "dfc"; break;
                    case 0x800: ea = "usp"; break;
                    case 0x801: ea = "vbr"; break;
                    default:    ea = "???"; break;
                }
                if (pm & 0x8000) sprintf(buffer, "movec    %s,%%a%ld", ea, (pm >> 12) & 7);
                else             sprintf(buffer, "movec    %s,%%d%ld", ea, (pm >> 12) & 7);
            }
            else if (lo == 0x3b) {
                PARAM_WORD(pm);
                switch (pm & 0xfff) {
                    case 0x000: ea = "sfc"; break;
                    case 0x001: ea = "dfc"; break;
                    case 0x800: ea = "usp"; break;
                    case 0x801: ea = "vbr"; break;
                    default:    ea = "???"; break;
                }
                if (pm & 0x8000) sprintf(buffer, "movec    %%a%ld,%s", (pm >> 12) & 7, ea);
                else             sprintf(buffer, "movec    %%a%ld,%s", (pm >> 12) & 7, ea);
            }
            else sprintf (buffer, "dc.w     0x%X", op);
            break;
        case 0x4e80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "jsr      %s", ea);
            break;
        case 0x4ec0:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "jmp      %s", ea);
            break;
        case 0x5000: case 0x5200: case 0x5400:
        case 0x5600: case 0x5800: case 0x5a00:
        case 0x5c00: case 0x5e00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "addq.b   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x5040: case 0x5240: case 0x5440:
        case 0x5640: case 0x5840: case 0x5a40:
        case 0x5c40: case 0x5e40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "addq.w   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x5080: case 0x5280: case 0x5480:
        case 0x5680: case 0x5880: case 0x5a80:
        case 0x5c80: case 0x5e80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "addq.l   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x50c0: case 0x52c0: case 0x54c0:
        case 0x56c0: case 0x58c0: case 0x5ac0:
        case 0x5cc0: case 0x5ec0: case 0x51c0:
        case 0x53c0: case 0x55c0: case 0x57c0:
        case 0x59c0: case 0x5bc0: case 0x5dc0:
        case 0x5fc0:
            if ((lo & 0x38) == 0x08) {
                PARAM_WORD(pm);
                if (pm & 0x8000) {
                    if (label_parse) {
                        AddLabel(pc + (signed short)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed short)pm + 2);

                        if (!s) {
                            sprintf(buffer, "db%s     %%d%d,*-0x%X  /*0x%lX*/",
                                    ccodes[(op >> 8) & 15], rlo,
                                    (int)(-(signed short)pm) - 2,
                                    pc + (signed short)pm) + 2;
                        }
                        else {
                            sprintf(buffer, "db%s     %%d%d, %s  /*-0x%X*/",
                                    ccodes[(op >> 8) & 15], rlo,
                                    s,(int)(-(signed short)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "db%s     %%d%d,*+0x%lX   /*0x%lX*/",
                                    ccodes[(op >> 8) & 15], rlo,
                                    pm - 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "db%s     %%d%d, %s  /*+0x%lX*/",
                                    ccodes[(op >> 8) & 15], rlo,
                                    s, pc + pm + 2);
                        }
                    }
                }
            }
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "s%s.b    %s", ccodes[(op >> 8) & 15], ea);
            }
            break;
        case 0x5100: case 0x5300: case 0x5500:
        case 0x5700: case 0x5900: case 0x5b00:
        case 0x5d00: case 0x5f00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "subq.b   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x5140: case 0x5340: case 0x5540:
        case 0x5740: case 0x5940: case 0x5b40:
        case 0x5d40: case 0x5f40:
            ea = MakeEA(lo, p, 2, &count); p += count;
            sprintf(buffer, "subq.w   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x5180: case 0x5380: case 0x5580:
        case 0x5780: case 0x5980: case 0x5b80:
        case 0x5d80: case 0x5f80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "subq.l   #%d,%s", (rhi == 0) ? 8 : rhi, ea);
            break;
        case 0x6000: case 0x6040: case 0x6080:
        case 0x60c0:
            pm = op & 0xff;
            if (pm == 0) {
                PARAM_WORD(pm);
                //if (IsROMAddr(pc + (signed short)pm + 2))
                //    sprintf(buffer, "bra      %s",ROMAddrName(pc + (signed short)pm + 2));
                if (pm & 0x8000) {
                    if (label_parse) {
                        AddLabel(pc + (signed short)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed short)pm + 2);
                        if (!s) {
                            sprintf(buffer, "bra      *-0x%X  /*0x%X*/",
                                (int)(-(signed short)pm) - 2,
                                pc + (signed short)pm + 2);
                        }
                        else {
                            sprintf(buffer, "bra      %s  /*-0x%X*/",
                                s,(int)(-(signed short)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);
                        if (!s) {
                            sprintf(buffer, "bra      *+0x%lX  /*0x%lX*/",
                                    pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "bra      %s  /*+0x%lX*/",
                                    s,pm + 2);
                        }
                    }
                }
            }
            else {
                //if (IsROMAddr(pc + (signed char)pm + 2)) sprintf(buffer, "bra.s    %s",ROMAddrName(pc + (signed char)pm + 2));
                if (pm & 0x80) {
                    if (label_parse) {
                        AddLabel(pc + (signed char)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed char)pm + 2);

                        if (!s) {
                            sprintf(buffer, "bra.s    *-0x%X  /*0x%X*/",
                                    (int)(-(signed char)pm) - 2,
                                     pc + (signed char)pm + 2);
                        }
                        else {
                            sprintf(buffer, "bra.s    %s  /*-0x%X*/",
                                    s,(int)(-(signed char)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "bra.s    *+0x%lX  /*0x%lX*/",
                                    pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "bra.s    %s  /*+0x%lX*/",
                                    s,pm + 2);
                        }
                    }
                }
            }
            break;
        case 0x6100: case 0x6140: case 0x6180:
        case 0x61c0:
            pm = op & 0xff;
            if (pm == 0) {
                PARAM_WORD(pm);
                //if (IsROMAddr(pc + (signed short)pm + 2)) sprintf(buffer, "bsr      %s",ROMAddrName(pc + (signed short)pm + 2));
                if (pm & 0x8000) {
                    if (label_parse) {
                        AddLabel(pc + (signed short)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed short)pm + 2);

                        if (!s) {
                            sprintf(buffer, "bsr      *-0x%X  /*0x%X*/",
                                    (int)(-(signed short)pm) - 2,
                                    pc + (signed short)pm + 2);
                        }
                        else {
                            sprintf(buffer, "bsr      %s  /*-0x%X*/",
                                    s,(int)(-(signed short)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "bsr      *+0x%lX  /*0x%lX*/",
                                    pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "bsr      %s  /*+0x%lX*/",
                                    s,pm + 2);
                        }
                    }
                }
            }
            else {
                //if (IsROMAddr(pc + (signed char)pm + 2))  sprintf(buffer, "bsr.s    %s",ROMAddrName(pc + (signed char)pm + 2));
                if (pm & 0x80) {
                    if (label_parse) {
                        AddLabel(pc + (signed char)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed char)pm + 2);

                        if (!s) {
                            sprintf(buffer, "bsr.s    *-0x%X  /*0x%X*/",
                                    (int)(-(signed char)pm) - 2,
                                    pc + (signed char)pm + 2);
                        }
                        else {
                            sprintf(buffer, "bsr.s    %s  /*-0x%X*/",
                                    s,(int)(-(signed char)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "bsr.s    *+0x%lX  /*0x%lX*/",
                                    pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "bsr.s    %s  /*+0x%lX*/",
                                    s,pm + 2);
                        }
                    }
                }
            }
            break;
        case 0x6200: case 0x6240: case 0x6280:
        case 0x62c0: case 0x6300: case 0x6340:
        case 0x6380: case 0x63c0: case 0x6400:
        case 0x6440: case 0x6480: case 0x64c0:
        case 0x6500: case 0x6540: case 0x6580:
        case 0x65c0: case 0x6600: case 0x6640:
        case 0x6680: case 0x66c0: case 0x6700:
        case 0x6740: case 0x6780: case 0x67c0:
        case 0x6800: case 0x6840: case 0x6880:
        case 0x68c0: case 0x6900: case 0x6940:
        case 0x6980: case 0x69c0: case 0x6a00:
        case 0x6a40: case 0x6a80: case 0x6ac0:
        case 0x6b00: case 0x6b40: case 0x6b80:
        case 0x6bc0: case 0x6c00: case 0x6c40:
        case 0x6c80: case 0x6cc0: case 0x6d00:
        case 0x6d40: case 0x6d80: case 0x6dc0:
        case 0x6e00: case 0x6e40: case 0x6e80:
        case 0x6ec0: case 0x6f00: case 0x6f40:
        case 0x6f80: case 0x6fc0:
            pm = op & 0xff;
            if (pm == 0) {
                PARAM_WORD(pm);
                //if (IsROMAddr(pc + (signed short)pm + 2)) sprintf(buffer, "b%s      %s",ccodes[(op >> 8) & 15], ROMAddrName(pc + (signed short)pm + 2));
                if (pm & 0x8000) {
                    if (label_parse) {
                        AddLabel(pc + (signed short)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed short)pm + 2);

                        if (!s) {
                            sprintf(buffer, "b%s      *-0x%X  /*0x%X*/",
                                    ccodes[(op >> 8) & 15],
                                    (int)(-(signed short)pm) - 2,
                                    pc + (signed short)pm + 2);
                        }
                        else {
                            sprintf(buffer, "b%s      %s  /*-0x%X*/",
                                    ccodes[(op >> 8) & 15],
                                    s,(int)(-(signed short)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "b%s      *+0x%lX  /*0x%lX*/",
                                    ccodes[(op >> 8) & 15], pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "b%s      %s  /*+0x%lX*/",
                                    ccodes[(op >> 8) & 15],s, pm + 2);
                        }
                    }
                }
            }
            else {
                //if (IsROMAddr(pc + (signed char)pm + 2))  sprintf(buffer, "b%s.s    %s",ccodes[(op >> 8) & 15], ROMAddrName(pc + (signed char)pm + 2));
                if (pm & 0x80) {
                    if (label_parse) {
                        AddLabel(pc + (signed char)pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + (signed char)pm + 2);

                        if (!s) {
                            sprintf(buffer, "b%s.s    *-0x%X  /*0x%X*/",
                                    ccodes[(op >> 8) & 15],
                                    (int)(-(signed char)pm) - 2,
                                    pc + (signed char)pm + 2);
                        }
                        else {
                            sprintf(buffer, "b%s.s    %s  /*-0x%X*/",
                                    ccodes[(op >> 8) & 15],
                                    s,(int)(-(signed char)pm) - 2);
                        }
                    }
                }
                else {
                    if (label_parse) {
                        AddLabel(pc + pm + 2);
                    }
                    else {
                        char* s = GetLabel(pc + pm + 2);

                        if (!s) {
                            sprintf(buffer, "b%s.s    *+0x%lX   /*0x%lX*/",
                                    ccodes[(op >> 8) & 15],
                                    pm + 2,
                                    pc + pm + 2);
                        }
                        else {
                            sprintf(buffer, "b%s.s    %s  /*+0x%lX*/",
                                    ccodes[(op >> 8) & 15],
                                    s,pm + 2);
                        }
                    }
                }
            }
            break;
        case 0x7000: case 0x7040: case 0x7080:
        case 0x70c0: case 0x7200: case 0x7240:
        case 0x7280: case 0x72c0: case 0x7400:
        case 0x7440: case 0x7480: case 0x74c0:
        case 0x7600: case 0x7640: case 0x7680:
        case 0x76c0: case 0x7800: case 0x7840:
        case 0x7880: case 0x78c0: case 0x7a00:
        case 0x7a40: case 0x7a80: case 0x7ac0:
        case 0x7c00: case 0x7c40: case 0x7c80:
        case 0x7cc0: case 0x7e00: case 0x7e40:
        case 0x7e80: case 0x7ec0:
            pm = op & 0xff;
            if (pm & 0x80) sprintf(buffer, "moveq    #-0x%X,%%d%d", -(signed char)pm, rhi);
            else           sprintf(buffer, "moveq    #0x%lX,%%d%d", pm, rhi);
            break;
        case 0x8000: case 0x8200: case 0x8400:
        case 0x8600: case 0x8800: case 0x8a00:
        case 0x8c00: case 0x8e00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "or.b     %s,%%d%d", ea, rhi);
            break;
        case 0x8040: case 0x8240: case 0x8440:
        case 0x8640: case 0x8840: case 0x8a40:
        case 0x8c40: case 0x8e40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "or.w     %s,%%d%d", ea, rhi);
            break;
        case 0x8080: case 0x8280: case 0x8480:
        case 0x8680: case 0x8880: case 0x8a80:
        case 0x8c80: case 0x8e80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "or.l     %s,%%d%d", ea, rhi);
            break;
        case 0x80c0: case 0x82c0: case 0x84c0:
        case 0x86c0: case 0x88c0: case 0x8ac0:
        case 0x8cc0: case 0x8ec0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "divu.w   %s,%%d%d", ea, rhi);
            break;
        case 0x8100: case 0x8300: case 0x8500:
        case 0x8700: case 0x8900: case 0x8b00:
        case 0x8d00: case 0x8f00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "or.b     %%d%d,%s", rhi, ea);
            break;
        case 0x8140: case 0x8340: case 0x8540:
        case 0x8740: case 0x8940: case 0x8b40:
        case 0x8d40: case 0x8f40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "or.w     %%d%d,%s", rhi, ea);
            break;
        case 0x8180: case 0x8380: case 0x8580:
        case 0x8780: case 0x8980: case 0x8b80:
        case 0x8d80: case 0x8f80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "or.l     %%d%d,%s", rhi, ea);
            break;
        case 0x81c0: case 0x83c0: case 0x85c0:
        case 0x87c0: case 0x89c0: case 0x8bc0:
        case 0x8dc0: case 0x8fc0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "divs.w   %s,%%d%d", ea, rhi);
            break;
        case 0x9000: case 0x9200: case 0x9400:
        case 0x9600: case 0x9800: case 0x9a00:
        case 0x9c00: case 0x9e00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "sub.b    %s,%%d%d", ea, rhi);
            break;
        case 0x9040: case 0x9240: case 0x9440:
        case 0x9640: case 0x9840: case 0x9a40:
        case 0x9c40: case 0x9e40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "sub.w    %s,%%d%d", ea, rhi);
            break;
        case 0x9080: case 0x9280: case 0x9480:
        case 0x9680: case 0x9880: case 0x9a80:
        case 0x9c80: case 0x9e80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "sub.l    %s,%%d%d", ea, rhi);
            break;
        case 0x90c0: case 0x92c0: case 0x94c0:
        case 0x96c0: case 0x98c0: case 0x9ac0:
        case 0x9cc0: case 0x9ec0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "suba.w   %s,%%a%d", ea, rhi);
            break;
        case 0x9100: case 0x9300: case 0x9500:
        case 0x9700: case 0x9900: case 0x9b00:
        case 0x9d00: case 0x9f00:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "subx.b   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "subx.b   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 1,&count);
                p += count;
                sprintf(buffer, "sub.b    %%d%d,%s", rhi, ea);
            }
            break;
        case 0x9140: case 0x9340: case 0x9540:
        case 0x9740: case 0x9940: case 0x9b40:
        case 0x9d40: case 0x9f40:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "subx.w   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "subx.w   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "sub.w    %%d%d,%s", rhi, ea);
            }
            break;
        case 0x9180: case 0x9380: case 0x9580:
        case 0x9780: case 0x9980: case 0x9b80:
        case 0x9d80: case 0x9f80:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "subx.l   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "subx.l   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                sprintf(buffer, "sub.l    %%d%d,%s", rhi, ea);
            }
            break;
        case 0x91c0: case 0x93c0: case 0x95c0:
        case 0x97c0: case 0x99c0: case 0x9bc0:
        case 0x9dc0: case 0x9fc0:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "suba.l   %s,%%a%d", ea, rhi);
            break;
        case 0xb000: case 0xb200: case 0xb400:
        case 0xb600: case 0xb800: case 0xba00:
        case 0xbc00: case 0xbe00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "cmp.b    %s,%%d%d", ea, rhi);
            break;
        case 0xb040: case 0xb240: case 0xb440:
        case 0xb640: case 0xb840: case 0xba40:
        case 0xbc40: case 0xbe40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "cmp.w    %s,%%d%d", ea, rhi);
            break;
        case 0xb080: case 0xb280: case 0xb480:
        case 0xb680: case 0xb880: case 0xba80:
        case 0xbc80: case 0xbe80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "cmp.l    %s,%%d%d", ea, rhi);
            break;
        case 0xb0c0: case 0xb2c0: case 0xb4c0:
        case 0xb6c0: case 0xb8c0: case 0xbac0:
        case 0xbcc0: case 0xbec0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "cmpa.w   %s,%%a%d", ea, rhi);
            break;
        case 0xb100: case 0xb300: case 0xb500:
        case 0xb700: case 0xb900: case 0xbb00:
        case 0xbd00: case 0xbf00:
            if ((lo & 0x38) == 0x08) sprintf(buffer, "cmpm.b   (%%a%d)+,(%%a%d)+", rlo, rhi);
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "eor.b    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xb140: case 0xb340: case 0xb540:
        case 0xb740: case 0xb940: case 0xbb40:
        case 0xbd40: case 0xbf40:
            if ((lo & 0x38) == 0x08) sprintf(buffer, "cmpm.w   (%%a%d)+,(%%a%d)+", rlo, rhi);
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "eor.w    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xb180: case 0xb380: case 0xb580:
        case 0xb780: case 0xb980: case 0xbb80:
        case 0xbd80: case 0xbf80:
            if ((lo & 0x38) == 0x08) sprintf(buffer, "cmpm.l   (%%a%d)+,(%%a%d)+", rlo, rhi);
            else {
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                sprintf(buffer, "eor.l    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xb1c0: case 0xb3c0: case 0xb5c0:
        case 0xb7c0: case 0xb9c0: case 0xbbc0:
        case 0xbdc0: case 0xbfc0:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "cmpa.l   %s,%%a%d", ea, rhi);
            break;
        case 0xc000: case 0xc200: case 0xc400:
        case 0xc600: case 0xc800: case 0xca00:
        case 0xcc00: case 0xce00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "and.b    %s,%%d%d", ea, rhi);
            break;
        case 0xc040: case 0xc240: case 0xc440:
        case 0xc640: case 0xc840: case 0xca40:
        case 0xcc40: case 0xce40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "and.w    %s,%%d%d", ea, rhi);
            break;
        case 0xc080: case 0xc280: case 0xc480:
        case 0xc680: case 0xc880: case 0xca80:
        case 0xcc80: case 0xce80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "and.l    %s,%%d%d", ea, rhi);
            break;
        case 0xc0c0: case 0xc2c0: case 0xc4c0:
        case 0xc6c0: case 0xc8c0: case 0xcac0:
        case 0xccc0: case 0xcec0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "mulu.w   %s,%%d%d", ea, rhi);
            break;
        case 0xc100: case 0xc300: case 0xc500:
        case 0xc700: case 0xc900: case 0xcb00:
        case 0xcd00: case 0xcf00:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "abcd.b   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "abcd.b   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "and.b    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xc140: case 0xc340: case 0xc540:
        case 0xc740: case 0xc940: case 0xcb40:
        case 0xcd40: case 0xcf40:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "exg      %%a%d,%%a%d", rhi, rlo);
                else           sprintf(buffer, "exg      %%d%d,%%d%d", rhi, rlo);
            }
            else {
                ea = MakeEA(lo, p, 2,&count);
                p += count;
                sprintf(buffer, "and.w    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xc180: case 0xc380: case 0xc580:
        case 0xc780: case 0xc980: case 0xcb80:
        case 0xcd80: case 0xcf80:
            if ((lo & 0x38) == 0x08) sprintf(buffer, "exg      %%d%d,%%a%d", rhi, rlo);
            else {
                ea = MakeEA(lo, p, 4, &count);
                p += count;
                sprintf(buffer, "and.l    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xc1c0: case 0xc3c0: case 0xc5c0:
        case 0xc7c0: case 0xc9c0: case 0xcbc0:
        case 0xcdc0: case 0xcfc0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "muls.w   %s,%%d%d", ea, rhi);
            break;
        case 0xd000: case 0xd200: case 0xd400:
        case 0xd600: case 0xd800: case 0xda00:
        case 0xdc00: case 0xde00:
            ea = MakeEA(lo, p, 1, &count);
            p += count;
            sprintf(buffer, "add.b    %s,%%d%d", ea, rhi);
            break;
        case 0xd040: case 0xd240: case 0xd440:
        case 0xd640: case 0xd840: case 0xda40:
        case 0xdc40: case 0xde40:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "add.w    %s,%%d%d", ea, rhi);
            break;
        case 0xd080: case 0xd280: case 0xd480:
        case 0xd680: case 0xd880: case 0xda80:
        case 0xdc80: case 0xde80:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "add.l    %s,%%d%d", ea, rhi);
            break;
        case 0xd0c0: case 0xd2c0: case 0xd4c0:
        case 0xd6c0: case 0xd8c0: case 0xdac0:
        case 0xdcc0: case 0xdec0:
            ea = MakeEA(lo, p, 2, &count);
            p += count;
            sprintf(buffer, "adda.w   %s,%%a%d", ea, rhi);
            break;
        case 0xd100: case 0xd300: case 0xd500:
        case 0xd700: case 0xd900: case 0xdb00:
        case 0xdd00: case 0xdf00:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "addx.b   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "addx.b   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 1, &count);
                p += count;
                sprintf(buffer, "add.b    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xd140: case 0xd340: case 0xd540:
        case 0xd740: case 0xd940: case 0xdb40:
        case 0xdd40: case 0xdf40:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "addx.w   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "addx.w   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 2, &count);
                p += count;
                sprintf(buffer, "add.w    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xd180: case 0xd380: case 0xd580:
        case 0xd780: case 0xd980: case 0xdb80:
        case 0xdd80: case 0xdf80:
            if ((lo & 0x30) == 0) {
                if (lo & 0x08) sprintf(buffer, "addx.l   -(%%a%d),-(%%a%d)", rlo, rhi);
                else           sprintf(buffer, "addx.l   %%d%d,%%d%d", rlo, rhi);
            }
            else {
                ea = MakeEA(lo, p, 4,&count);
                p += count;
                sprintf(buffer, "add.l    %%d%d,%s", rhi, ea);
            }
            break;
        case 0xd1c0: case 0xd3c0: case 0xd5c0:
        case 0xd7c0: case 0xd9c0: case 0xdbc0:
        case 0xddc0: case 0xdfc0:
            ea = MakeEA(lo, p, 4, &count);
            p += count;
            sprintf(buffer, "adda.l   %s,%%a%d", ea, rhi);
            break;
        case 0xe000: case 0xe200: case 0xe400:
        case 0xe600: case 0xe800: case 0xea00:
        case 0xec00: case 0xee00:
            switch ((lo >> 3) & 7) {
                case 0: sprintf(buffer, "asr.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                case 1: sprintf(buffer, "lsr.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                case 2: sprintf(buffer, "roxr.b   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                case 3: sprintf(buffer, "ror.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                case 4: sprintf(buffer, "asr.b    %%d%d,%%d%d", rhi, rlo); break;
                case 5: sprintf(buffer, "lsr.b    %%d%d,%%d%d", rhi, rlo); break;
                case 6: sprintf(buffer, "roxr.b   %%d%d,%%d%d", rhi, rlo); break;
                case 7: sprintf(buffer, "ror.b    %%d%d,%%d%d", rhi, rlo); break;
            }
            break;
        case 0xe040: case 0xe240: case 0xe440:
        case 0xe640: case 0xe840: case 0xea40:
        case 0xec40: case 0xee40:
            switch ((lo >> 3) & 7) {
                case 0: sprintf(buffer, "asr.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                case 1: sprintf(buffer, "lsr.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 2: sprintf(buffer, "roxr.w   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 3: sprintf(buffer, "ror.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 4: sprintf(buffer, "asr.w    %%d%d,%%d%d", rhi, rlo); break;
                                case 5: sprintf(buffer, "lsr.w    %%d%d,%%d%d", rhi, rlo); break;
                                case 6: sprintf(buffer, "roxr.w   %%d%d,%%d%d", rhi, rlo); break;
                                case 7: sprintf(buffer, "ror.w    %%d%d,%%d%d", rhi, rlo); break;
                        }
                        break;
                case 0xe080: case 0xe280: case 0xe480:
                case 0xe680: case 0xe880: case 0xea80:
                case 0xec80: case 0xee80:
                        switch ((lo >> 3) & 7) {
                                case 0: sprintf(buffer, "asr.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 1: sprintf(buffer, "lsr.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 2: sprintf(buffer, "roxr.l   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 3: sprintf(buffer, "ror.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 4: sprintf(buffer, "asr.l    %%d%d,%%d%d", rhi, rlo); break;
                                case 5: sprintf(buffer, "lsr.l    %%d%d,%%d%d", rhi, rlo); break;
                                case 6: sprintf(buffer, "roxr.l   %%d%d,%%d%d", rhi, rlo); break;
                                case 7: sprintf(buffer, "ror.l    %%d%d,%%d%d", rhi, rlo); break;
                        }
                        break;
                case 0xe0c0: case 0xe2c0: case 0xe4c0:
                case 0xe6c0: case 0xe1c0: case 0xe3c0:
                case 0xe5c0: case 0xe7c0:
                        ea = MakeEA(lo, p, 4, &count);
                        p += count;
                        switch ((op >> 8) & 7) {
                                case 0: sprintf(buffer, "asr.l    #1,%s", ea); break;
                                case 1: sprintf(buffer, "asl.l    #1,%s", ea); break;
                                case 2: sprintf(buffer, "lsr.l    #1,%s", ea); break;
                                case 3: sprintf(buffer, "lsl.l    #1,%s", ea); break;
                                case 4: sprintf(buffer, "roxr.l   #1,%s", ea); break;
                                case 5: sprintf(buffer, "roxl.l   #1,%s", ea); break;
                                case 6: sprintf(buffer, "ror.l    #1,%s", ea); break;
                                case 7: sprintf(buffer, "rol.l    #1,%s", ea); break;
                        }
                        break;
                case 0xe100: case 0xe300: case 0xe500:
                case 0xe700: case 0xe900: case 0xeb00:
                case 0xed00: case 0xef00:
                        switch ((lo >> 3) & 7) {
                                case 0: sprintf(buffer, "asl.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 1: sprintf(buffer, "lsl.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 2: sprintf(buffer, "roxl.b   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 3: sprintf(buffer, "rol.b    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 4: sprintf(buffer, "asl.b    %%d%d,%%d%d", rhi, rlo); break;
                                case 5: sprintf(buffer, "lsl.b    %%d%d,%%d%d", rhi, rlo); break;
                                case 6: sprintf(buffer, "roxl.b   %%d%d,%%d%d", rhi, rlo); break;
                                case 7: sprintf(buffer, "rol.b    %%d%d,%%d%d", rhi, rlo); break;
                        }
                        break;
                case 0xe140: case 0xe340: case 0xe540:
                case 0xe740: case 0xe940: case 0xeb40:
                case 0xed40: case 0xef40:
                        switch ((lo >> 3) & 7) {
                                case 0: sprintf(buffer, "asl.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 1: sprintf(buffer, "lsl.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 2: sprintf(buffer, "roxl.w   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 3: sprintf(buffer, "rol.w    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 4: sprintf(buffer, "asl.w    %%d%d,%%d%d", rhi, rlo); break;
                                case 5: sprintf(buffer, "lsl.w    %%d%d,%%d%d", rhi, rlo); break;
                                case 6: sprintf(buffer, "roxl.w   %%d%d,%%d%d", rhi, rlo); break;
                                case 7: sprintf(buffer, "rol.w    %%d%d,%%d%d", rhi, rlo); break;
                        }
                        break;
                case 0xe180: case 0xe380: case 0xe580:
                case 0xe780: case 0xe980: case 0xeb80:
                case 0xed80: case 0xef80:
                        switch ((lo >> 3) & 7) {
                                case 0: sprintf(buffer, "asl.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 1: sprintf(buffer, "lsl.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 2: sprintf(buffer, "roxl.l   #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 3: sprintf(buffer, "rol.l    #%d,%%d%d", (rhi == 0) ? 8 : rhi, rlo); break;
                                case 4: sprintf(buffer, "asl.l    %%d%d,%%d%d", rhi, rlo); break;
                                case 5: sprintf(buffer, "lsl.l    %%d%d,%%d%d", rhi, rlo); break;
                                case 6: sprintf(buffer, "roxl.l   %%d%d,%%d%d", rhi, rlo); break;
                                case 7: sprintf(buffer, "rol.l    %%d%d,%%d%d", rhi, rlo); break;
                        }
                        break;
                default:
                        sprintf(buffer, "dc.w     0x%X", op);
                        break;
        }

        return p - pBase;
}



//=============================================================================
// disassemble given buffer until length bytes are processed
// the given offset is used just for the address output in the comment
//=============================================================================
void Disassemble(unsigned char* mem,int length,int used_offset,
                 int virtual_offset,int show_possible)
{
    char buffer[1024];
    int  start = 0;
    int  bytes;
    int  i;

    //printf("starting ...\n");

    if (!no_labels) {
        label_parse=1;
        while (start < length) {
            bytes = Dasm68000(mem+start,buffer,start+used_offset+virtual_offset);

            if (!label_parse) {
                printf("ERROR: OUT-OF-MEMORY - cannot add that much levels\n");
                return;
            }
            start+=bytes;
        }

        start       = 0;
        label_parse = 0;
    }

    printf("asm(\"\n");

    while (start < length) {
        if (!no_labels) {
            char* s = GetLabel(start+used_offset+virtual_offset);
            if (s) printf("%s:\n",s);
        }
        bytes = Dasm68000(mem+start,buffer,start+used_offset+virtual_offset);
        printf("%s",buffer);
        for (i=strlen(buffer);i<30;i++) printf(" ");
        printf("/* [0x%X (%u)] ",start+used_offset+virtual_offset,start+used_offset+virtual_offset);
        for (i=0;i<bytes;i++) printf("%02x ",*(mem+start+i));
        for (i=bytes;i<6;i++) printf("   ");
        if (show_possible) {
            if (offsetname_ptr) printf("?%s? */\n",offsetname_ptr);
            else                printf("*/\n");
        }
        else {
            printf("*/\n");
        }
        start+=bytes;
    }
    printf("\");\n");
}


//=============================================================================
// outputs header details of kernel-based programs or libraries
//=============================================================================
void OutputStubDetails(unsigned char* mem, int used_offset,int virtual_offset) {
    int i,offset,count;
    printf("******** STUB-HEADER INFO *********\n");

    if ((!strncmp(mem+4,"68kP",4)) || (!strncmp(mem+4,"68kL",4))) {
        printf("signature:        %c%c%c%c\n",*(mem+4),*(mem+5),*(mem+6),*(mem+7));

        printf("relcount:         %d\n",GET_WORD(mem+8));
        printf("offset comment:   0x%04x\n",GET_WORD(mem+0xa));
        printf("offset main:      0x%04x\n",GET_WORD(mem+0xc));
        printf("offset exit:      0x%04x\n",GET_WORD(mem+0xe));
        printf("compatiblity:     0x%04x\n",GET_WORD(mem+0x10));
        printf("offset BSS:       0x%04x\n",GET_WORD(mem+0x14));
        offset = GET_WORD(mem+0x16);
        printf("offset export:    0x%04x\n",offset);
        printf("offset RAM table: 0x%04x\n",GET_WORD(mem+0x18));
        printf("********* EXPORT TABLE ************\n");
        count = GET_WORD(mem+offset);
        for (i=0;i<count;i++) printf("export@%04x:      0x%04x\n",i,GET_WORD(mem+offset+2+i*2));
    }
    else {
        printf("--- not found --- (missing 68kP or 68kL)\n");
    }
}


//=============================================================================
// its a main ...
//=============================================================================
int main(int argc,char *argv[]) {
    char*          infile = 0;
    FILE*          ifp;
    char           sig[9];
    int            length;
    unsigned char* data;
    int            n;
    int            given_offset            = -1;
    int            given_length            = -1;
    char*          given_rom               = 0;
    int            show_functions          = 0;
    int            show_possible_functions = 0;
    int            virtual_offset          = 0;
    int            raw                     = 0;
    int            vti                     = 0;
    int            stub                    = 0;

    PRINT_ID("TTDasm");

    //---------------------------------------------------------------
    // check for too less arguments
    //---------------------------------------------------------------
    if (argc < 2) {
        PrintUsage();
        return 1;
    }

    //---------------------------------------------------------------
    // parse commandline arguments
    //---------------------------------------------------------------
    for (n=1; n<argc; n++) {
        if (!strcmp(argv[n], "-o")) {
            // handle offset commandline tag
            if (n == argc -1) {
                PrintUsage();
                return 1;
            }
            else {
                if (!strncmp(argv[n+1],"0x",2)) {
                    if (sscanf(&argv[n+1][2],"%x",&given_offset) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                else {
                    if (sscanf(argv[n+1],"%d",&given_offset) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                if (given_offset<0) {
                    fprintf(stderr,"ERROR: offset cannot be negative\n");
                    return 1;
                }
                n++;
            }
        }
        else if (!strcmp(argv[n], "-virtual")) {
            // handle virtual offset commandline tag
            if (n == argc -1) {
                PrintUsage();
                return 1;
            }
            else {
                if (!strncmp(argv[n+1],"0x",2)) {
                    if (sscanf(&argv[n+1][2],"%x",&virtual_offset) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                else {
                    if (sscanf(argv[n+1],"%d",&virtual_offset) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                if (virtual_offset<0) {
                    fprintf(stderr,"ERROR: offset cannot be negative\n");
                    return 1;
                }
                n++;
            }
        }
        else if (!strcmp(argv[n], "-l")) {
            // handle length commandline tag
            if (n == argc -1) {
                PrintUsage();
                return 1;
            }
            else {
                if (!strncmp(argv[n+1],"0x",2)) {
                    if (sscanf(&argv[n+1][2],"%x",&given_length) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                else {
                    if (sscanf(argv[n+1],"%d",&given_length) != 1) {
                        PrintUsage();
                        return 1;
                    }
                }
                if (given_length<0) {
                    fprintf(stderr,"ERROR: length cannot be negative\n");
                    return 1;
                }
                n++;
            }
        }
        else if (!strcmp(argv[n], "-r")) {
            // handle romfile commandline tag
            if (n == argc -1) {
                PrintUsage();
                return 1;
            }
            else {
                given_rom = argv[n+1];
                n++;
            }
        }
        else if (!strcmp(argv[n], "-f")) {
            // handle show ROM functions commandline tag
            show_functions = 1;
        }
        else if (!strcmp(argv[n], "-vti")) {
            // handle show ROM functions commandline tag
            vti = 1;
            if (raw || given_rom) {
                fprintf(stderr,"ERROR: cannot use -vti with -r or -raw\n");
                return 1;
            }
        }
        else if (!strcmp(argv[n], "-stub")) {
            // shows additionally informations about kernel based programs
            stub = 1;
        }
        else if (!strcmp(argv[n], "-raw")) {
            // handle show ROM functions commandline tag
            raw = 1;
            if (vti || given_rom) {
                fprintf(stderr,"ERROR: cannot use -raw with -r or -vti\n");
                return 1;
            }
        }
        else if (!strcmp(argv[n], "-name")) {
            // handle show possible ROM functions commandline tag
            show_possible_functions = 1;
        }
        else if (!strcmp(argv[n], "-nolabels")) {
            // handle show possible ROM functions commandline tag
            no_labels = 1;
        }
        else if (argv[n][0] == '-') {
            fprintf(stderr,"ERROR: invalid option %s",argv[n]);
            return 1;
        }

        else if (!infile) infile = argv[n];
        else {
            PrintUsage();
            return 1;
        }
    }

    //---------------------------------------------------------------
    // some parameter validation checks
    //---------------------------------------------------------------
    if (!infile && !given_rom) {
        fprintf(stderr,"ERROR: neither file nor ROM is given\n");
        return 1;
    }

    if (infile && given_rom) {
        fprintf(stderr,"ERROR: cannot use file and ROM at the same time\n");
        return 1;
    }

    if (show_functions && infile) {
        fprintf(stderr,"WARNING: cannot show ROM functions (only possible with given ROM)\n");
    }


    //---------------------------------------------------------------
    // load ROM file if user had supplied a ROM filename
    //---------------------------------------------------------------
    if (given_rom) {
        if (!LoadROM(given_rom)) {
            fprintf(stderr,"/*[program terminated due to ROM loading error]*/\n");
            return 1;
        }
        InitMemoryPointers();
    }

    InitializeROMFuncs((given_rom)?1:0);

    //----------------------------------------------------
    // treat ROM disassembling
    //----------------------------------------------------
    if (given_rom) {
        if (show_functions) {
            int i;
            for (i=0;romFuncs[i].name;i++) {
                printf("%06x (%07d) %s\n",romFuncAddr[i],romFuncAddr[i],romFuncs[i].name);
            }
            CleanupROM();
            return 0;
        }


        if (given_offset == -1 || given_length == -1) {
            fprintf(stderr,"ERROR: please specify offset and length\n");
            CleanupROM();
            return 1;
        }

        if (!(data = malloc(given_length+20))) {
            fprintf(stderr,"ERROR: cannot allocate %d bytes\n",given_length+20);
            CleanupROM();
            return 1;
        }

        for (n=0;n<given_length;n++) data[n] = getmem(given_offset+n);

        Disassemble(data,given_length,given_offset,virtual_offset,show_possible_functions);
        if (label_list) free(label_list);
        CleanupROM();
        free(data);
        return 0;
    }

    //----------------------------------------------------
    // if we'll come here user wants to disassemble a file
    //----------------------------------------------------
    if (!(ifp = fopen(infile,"rb"))) {
        fprintf(stderr,"ERROR: cannot open inputfile %s\n",infile);
        if (given_rom) CleanupROM();
        return 1;
    }

    if (!vti && !raw) {
        memset(sig,0,9);
        fread(sig,1,8,ifp);

        if (strcmp(sig,SIGNATURE_TI89) && strcmp(sig,SIGNATURE_TI92P)) {
            fprintf(stderr,"ERROR: neither TI89 nor TI92p executable\n");
            fclose(ifp);
            if (given_rom) CleanupROM();
            return 1;
        }
    }

    fseek(ifp,0,SEEK_END);
    length = ftell(ifp);

    if (vti) {
        length -= 0x100;
        if (given_offset != -1 && given_offset >= 256000) {
            fprintf(stderr,"ERROR: given offset is too large (%d >= 256000)\n",given_offset);
            fclose(ifp);
            if (given_rom) CleanupROM();
            return 1;
        }
        if (length < 256000+0x100) {
            fprintf(stderr,"ERROR: given file no valid VTI save file (too short)\n");
            fclose(ifp);
            if (given_rom) CleanupROM();
            return 1;
        }
    }
    else {
        if (!raw) {
            length -= 90; // 86 bytes for header + 2 bytes for length + 2 bytes for trailing checksum
        }
        if (given_offset != -1 && given_offset >= length) {
            fprintf(stderr,"ERROR: given offset is too large (%d >= %d)\n",given_offset,length);
            fclose(ifp);
            if (given_rom) CleanupROM();
            return 1;
        }

        if (given_length != -1 && given_length >= length) {
            fprintf(stderr,"ERROR: given length is too large (%d >= %d)\n",given_length,length);
            fclose(ifp);
            if (given_rom) CleanupROM();
            return 1;
        }
    }

    rewind(ifp);
    if (!raw) {
        if (vti) fseek(ifp,0x100,SEEK_SET);
        else     fseek(ifp,88,SEEK_SET);
    }

    if (!(data = malloc(length+20))) {
        fprintf(stderr,"ERROR: cannot allocate %d bytes\n",length+20);
        fclose(ifp);
        if (given_rom) CleanupROM();
        return 1;
    }

    memset(data,0,length+20);
    fread(data,1,length,ifp);
    fclose(ifp);

    if (given_length != -1) length = given_length;
    if (given_offset == -1) given_offset = 0;

    if (stub) OutputStubDetails(data+given_offset,given_offset,virtual_offset);

    Disassemble(data+given_offset,length,given_offset,virtual_offset,show_possible_functions);
    if (label_list) free(label_list);

    if (given_rom) CleanupROM();
    free(data);
    return 0;
}

//#############################################################################
//###################### NO MORE FAKES BEYOND THIS LINE #######################
//#############################################################################
//
//=============================================================================
// Revision History
//=============================================================================
//
// $Log: ttdasm.c,v $
// Revision 1.6  2002/02/07 09:49:37  tnussb
// all local includes changed, because header files are now located in pctools folder
//
// Revision 1.5  2001/07/31 22:57:46  Thomas Nussbaumer
// generic commit for Tools Suite version 0.99.10
//
// Revision 1.4  2001/02/10 20:13:22  Thomas Nussbaumer
// (1) support for raw dumps added
// (2) support for VTI save files added
// (3) commandline switch -nolabels added
// (4) generates now labels for PC-relative stuff, too
// (5) some bug fixes related to label generation
//
// Revision 1.3  2001/02/09 18:56:58  Thomas Nussbaumer
// (1) generates labels automatically
// (2) generates compile-able code
// (3) "-virtual" commandline flag added (adding just an virtual offset)
// (4) "-name" commandline flag added (turns on hints about possible ROM calls)
//
// Revision 1.2  2000/11/28 00:08:29  Thomas Nussbaumer
// using now USAGE_OUT stream for usage info
//
// Revision 1.1  2000/10/01 15:02:23  Thomas Nussbaumer
// initial version
//
//
    