├── eZDisasm ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── readme.txt ├── eZDisasm.csproj ├── Program.cs └── eZ80Disassembler.cs ├── eZDisasm.sln ├── .gitattributes └── .gitignore /eZDisasm/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /eZDisasm.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "eZDisasm", "eZDisasm\eZDisasm.csproj", "{30FBE45C-829F-4EB6-94E3-25EB465088F4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {30FBE45C-829F-4EB6-94E3-25EB465088F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {30FBE45C-829F-4EB6-94E3-25EB465088F4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {30FBE45C-829F-4EB6-94E3-25EB465088F4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {30FBE45C-829F-4EB6-94E3-25EB465088F4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /eZDisasm/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("eZDisasm")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("eZDisasm")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("bcc2bc62-9c40-4fe2-984d-5ad64d616194")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /eZDisasm/readme.txt: -------------------------------------------------------------------------------- 1 | eZ80 Disassembler 2 | 19 August 2015 3 | 4 | Usage: eZDisasm [-options] [-b ] [-o ] 5 | OR eZDisasm [-options] [-b ] [-o ] -i file.txt 6 | OR eZDisasm [-options] [-b ] [-o ] -I file.bin 7 | Output disassembly is dumped to stdout. 8 | 9 | Options: 10 | -a, --short-mode 11 | Use short mode, not ADL mode 12 | Transitions between short and long mode are not handled 13 | -b
, --base-address 14 | Set base address for disassembly, address is in hexadecimal 15 | -c, --irc-mode 16 | Output onto one continuous line 17 | -d, --show-addresses 18 | Prefix every instruction with its address 19 | -E, --eZ80 (default) 20 | Set eZ80 disassembly mode 21 | -e, --Z80 22 | Set classic Z80 disassembly mode, implies -a 23 | -g, --ascii 24 | Convert input into ASCII .db statements instead of disassembly 25 | -h, --hex-dump 26 | Convert input into hex .db statements instead of disassembly 27 | -H, --word-dump 28 | Convert input into hex .dw statements instead of disassembly 29 | NOTE: This will print 24-bit words unless -A or -e is set 30 | -i , --infile 31 | Read instructions in hex from 32 | -I , --binfile 33 | Read instructions in binary format from 34 | -k , --line-length 35 | For -h or -H, print bytes/words per line 36 | -K , --line-length-hex 37 | Same as -k but input in hexadecimal 38 | -l, --no-labels 39 | Do not add labels for branches 40 | -n, --stdin 41 | Read input from stdin 42 | -O (default), --stdout 43 | Write output to stdout, not mutually exclusive with -o 44 | -o , --outfile 45 | Write output to instead of stdout. 46 | -P, --no-pause (default) 47 | Do not pause to wait for a key when done 48 | -p, --pause 49 | Pause when done 50 | -r
, --from
51 | Start disassembly range at
52 | -R
, --to
53 | Stop disassembly range at
54 | -s, --pad-tabs 55 | Use tabs for column alignment instead of spaces 56 | -t, --no-align 57 | Do not align instruction arguments 58 | -x, --hide-opcodes 59 | Do not show instruction opcodes 60 | -z, --no-append 61 | Do not append to outfile; instead overwrite it -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /eZDisasm/eZDisasm.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {30FBE45C-829F-4EB6-94E3-25EB465088F4} 8 | Exe 9 | Properties 10 | eZDisasm 11 | eZDisasm 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | TRACE;DEBUG;WIN_32 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE;WIN_32 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # Roslyn cache directories 20 | *.ide/ 21 | 22 | # MSTest test Results 23 | [Tt]est[Rr]esult*/ 24 | [Bb]uild[Ll]og.* 25 | 26 | #NUNIT 27 | *.VisualState.xml 28 | TestResult.xml 29 | 30 | # Build Results of an ATL Project 31 | [Dd]ebugPS/ 32 | [Rr]eleasePS/ 33 | dlldata.c 34 | 35 | *_i.c 36 | *_p.c 37 | *_i.h 38 | *.ilk 39 | *.meta 40 | *.obj 41 | *.pch 42 | *.pdb 43 | *.pgc 44 | *.pgd 45 | *.rsp 46 | *.sbr 47 | *.tlb 48 | *.tli 49 | *.tlh 50 | *.tmp 51 | *.tmp_proj 52 | *.log 53 | *.vspscc 54 | *.vssscc 55 | .builds 56 | *.pidb 57 | *.svclog 58 | *.scc 59 | 60 | # Chutzpah Test files 61 | _Chutzpah* 62 | 63 | # Visual C++ cache files 64 | ipch/ 65 | *.aps 66 | *.ncb 67 | *.opensdf 68 | *.sdf 69 | *.cachefile 70 | 71 | # Visual Studio profiler 72 | *.psess 73 | *.vsp 74 | *.vspx 75 | 76 | # TFS 2012 Local Workspace 77 | $tf/ 78 | 79 | # Guidance Automation Toolkit 80 | *.gpState 81 | 82 | # ReSharper is a .NET coding add-in 83 | _ReSharper*/ 84 | *.[Rr]e[Ss]harper 85 | *.DotSettings.user 86 | 87 | # JustCode is a .NET coding addin-in 88 | .JustCode 89 | 90 | # TeamCity is a build add-in 91 | _TeamCity* 92 | 93 | # DotCover is a Code Coverage Tool 94 | *.dotCover 95 | 96 | # NCrunch 97 | _NCrunch_* 98 | .*crunch*.local.xml 99 | 100 | # MightyMoose 101 | *.mm.* 102 | AutoTest.Net/ 103 | 104 | # Web workbench (sass) 105 | .sass-cache/ 106 | 107 | # Installshield output folder 108 | [Ee]xpress/ 109 | 110 | # DocProject is a documentation generator add-in 111 | DocProject/buildhelp/ 112 | DocProject/Help/*.HxT 113 | DocProject/Help/*.HxC 114 | DocProject/Help/*.hhc 115 | DocProject/Help/*.hhk 116 | DocProject/Help/*.hhp 117 | DocProject/Help/Html2 118 | DocProject/Help/html 119 | 120 | # Click-Once directory 121 | publish/ 122 | 123 | # Publish Web Output 124 | *.[Pp]ublish.xml 125 | *.azurePubxml 126 | ## TODO: Comment the next line if you want to checkin your 127 | ## web deploy settings but do note that will include unencrypted 128 | ## passwords 129 | #*.pubxml 130 | 131 | # NuGet Packages Directory 132 | packages/* 133 | ## TODO: If the tool you use requires repositories.config 134 | ## uncomment the next line 135 | #!packages/repositories.config 136 | 137 | # Enable "build/" folder in the NuGet Packages folder since 138 | # NuGet packages use it for MSBuild targets. 139 | # This line needs to be after the ignore of the build folder 140 | # (and the packages folder if the line above has been uncommented) 141 | !packages/build/ 142 | 143 | # Windows Azure Build Output 144 | csx/ 145 | *.build.csdef 146 | 147 | # Windows Store app package directory 148 | AppPackages/ 149 | 150 | # Others 151 | sql/ 152 | *.Cache 153 | ClientBin/ 154 | [Ss]tyle[Cc]op.* 155 | ~$* 156 | *~ 157 | *.dbmdl 158 | *.dbproj.schemaview 159 | *.pfx 160 | *.publishsettings 161 | node_modules/ 162 | 163 | # RIA/Silverlight projects 164 | Generated_Code/ 165 | 166 | # Backup & report files from converting an old project file 167 | # to a newer Visual Studio version. Backup files are not needed, 168 | # because we have git ;-) 169 | _UpgradeReport_Files/ 170 | Backup*/ 171 | UpgradeLog*.XML 172 | UpgradeLog*.htm 173 | 174 | # SQL Server files 175 | *.mdf 176 | *.ldf 177 | 178 | # Business Intelligence projects 179 | *.rdl.data 180 | *.bim.layout 181 | *.bim_*.settings 182 | 183 | # Microsoft Fakes 184 | FakesAssemblies/ 185 | 186 | # LightSwitch generated files 187 | GeneratedArtifacts/ 188 | _Pvt_Extensions/ 189 | ModelManifest.xml -------------------------------------------------------------------------------- /eZDisasm/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using System.Reflection; 8 | using System.Text.RegularExpressions; 9 | #if WIN_32 10 | using System.Runtime.InteropServices; 11 | #endif 12 | 13 | // Could be useful to add an option for reading from stdin. 14 | // Also, a way to only read from part of a .bin. 15 | // And a way to specify append, not overwrite, for outfile. 16 | // Also support --argname in addition to single-char switches. 17 | 18 | namespace eZDisasm 19 | { 20 | class Program 21 | { 22 | #if WIN_32 23 | 24 | [DllImport("kernel32.dll", SetLastError = true)] 25 | static extern uint GetConsoleProcessList(uint[] ProcessList, uint ProcessCount); 26 | #endif 27 | enum ArgumentType 28 | { 29 | BaseAddress, 30 | InputFile, 31 | BinaryInputFile, 32 | OutputFile, 33 | 34 | } 35 | 36 | enum StringArgumentType 37 | { 38 | BaseAddress, 39 | InputFileName, 40 | OutputFileName, 41 | StartAddress, 42 | EndAddress, 43 | } 44 | 45 | enum ErrorCode 46 | { 47 | NoError, 48 | NoArguments, 49 | BadArgument, 50 | ConflictingArgument, 51 | DuplicateArgument, 52 | MissingImpliedArgument, 53 | InvalidHexString, 54 | FileOpenError, 55 | } 56 | 57 | static bool pause = false; 58 | 59 | #if WIN_32 60 | static bool newConsole = false; 61 | #endif 62 | 63 | static int Main(string[] args) 64 | { 65 | #if WIN_32 66 | // Don't call Win32 functions from Mono 67 | if (Type.GetType("Mono.Runtime") == null) 68 | // Are we the only process using this console? 69 | switch (GetConsoleProcessList(new uint[] { 0 }, 1)) 70 | { 71 | case 0: 72 | Console.WriteLine("Internal error: Could not get console process list."); 73 | break; 74 | case 1: 75 | // Yes, we are the only process using this console, so 76 | // hold it open when done unless overridden with --no-pause 77 | newConsole = pause = true; 78 | break; 79 | default: 80 | pause = false; 81 | break; 82 | } 83 | #endif 84 | // Parse arguments 85 | if (args.Length == 0) 86 | { 87 | ShowHelp(false); 88 | return (int)ErrorCode.NoArguments; 89 | } 90 | 91 | int curArg = 0; 92 | 93 | int baseAddress = 0; 94 | bool hasBaseAddress = false; 95 | bool readInputFile = false; 96 | bool binaryInputFile = false; 97 | string inputFileName = ""; 98 | bool z80ClassicMode = false; 99 | bool adlMode = true; 100 | bool addLabels = true; 101 | bool showOpcodes = true; 102 | bool alignArgs = true; 103 | bool useTabs = false; 104 | bool showAddresses = false; 105 | bool forceWriteStdOut = false; 106 | bool writeStdOut = true; 107 | bool writeOutputFile = false; 108 | bool stdin = false; 109 | string outputFileName = ""; 110 | bool ircMode = false; 111 | bool append = true; 112 | int start = 0; 113 | bool haveStart = false; 114 | int end = 0; 115 | bool haveEnd = false; 116 | bool dumpMode = false; 117 | bool hexMode = true; 118 | bool wordMode = false; 119 | 120 | #region Parse Arguments 121 | Queue expectedArgs = new Queue(); 122 | 123 | Action seteZ80Mode = () => z80ClassicMode = false; 124 | Action setZ80Mode = () => { z80ClassicMode = true; adlMode = false; }; 125 | Action setShortMode = () => adlMode = false; 126 | Action setShowLabels = () => addLabels = true; 127 | Action unsetShowLabels = () => addLabels = false; 128 | Action setAlignArgs = () => alignArgs = true; 129 | Action unsetAlignArgs = () => alignArgs = false; 130 | Action setUseTabs = () => useTabs = true; 131 | Action unsetUseTabs = () => useTabs = false; 132 | Action setIrcMode = () => ircMode = true; 133 | Action unsetIrcMode = () => ircMode = false; 134 | Action setStdIn = () => stdin = true; 135 | Action setWriteStdOut = () => writeStdOut = forceWriteStdOut = true; 136 | Action setShowAddresses = () => showAddresses = true; 137 | Action unsetShowAddresses = () => showAddresses = false; 138 | Action setShowOpcodes = () => showOpcodes = true; 139 | Action unsetShowOpcodes = () => showOpcodes = false; 140 | Action setPause = () => pause = true; 141 | Action unsetPause = () => pause = false; 142 | Action setAppend = () => append = true; 143 | Action unsetAppend = () => append = false; 144 | Action setLongMode = () => 145 | { 146 | if (z80ClassicMode) 147 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: -A is mutually exclusive with -e"); 148 | adlMode = true; 149 | }; 150 | Action setWriteOutFile = () => 151 | { 152 | if (writeOutputFile) 153 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate outfile specifier"); 154 | if (!forceWriteStdOut) 155 | writeStdOut = false; 156 | writeOutputFile = true; 157 | expectedArgs.Enqueue(StringArgumentType.OutputFileName); 158 | }; 159 | Action setBaseAddress = () => 160 | { 161 | if (hasBaseAddress) 162 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate base address specifier"); 163 | hasBaseAddress = true; 164 | expectedArgs.Enqueue(StringArgumentType.BaseAddress); 165 | }; 166 | Action setReadFile = () => 167 | { 168 | if (readInputFile) 169 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate infile specifier"); 170 | if (stdin) 171 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: -i is mutually exclusive with with -n"); 172 | readInputFile = true; 173 | binaryInputFile = false; 174 | expectedArgs.Enqueue(StringArgumentType.InputFileName); 175 | }; 176 | Action setBinFile = () => 177 | { 178 | if (readInputFile) 179 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate infile specifier"); 180 | if (stdin) 181 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: -I is mutually exclusive with with -n"); 182 | readInputFile = true; 183 | binaryInputFile = true; 184 | expectedArgs.Enqueue(StringArgumentType.InputFileName); 185 | }; 186 | Action setStartAddr = () => 187 | { 188 | if (start != 0) 189 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate start address"); 190 | expectedArgs.Enqueue(StringArgumentType.StartAddress); 191 | haveStart = true; 192 | }; 193 | Action setEndAddr = () => 194 | { 195 | if (end != 0) 196 | ShowShortHelp(ErrorCode.DuplicateArgument, "Error: Duplicate end address"); 197 | expectedArgs.Enqueue(StringArgumentType.EndAddress); 198 | haveEnd = true; 199 | }; 200 | Action setHexMode = () => 201 | { 202 | if (wordMode) 203 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: Byte hex mode is mutually exclusive with word hex mode"); 204 | if (dumpMode) 205 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: Hex mode is mutually exclusive with ASCII mode"); 206 | dumpMode = true; 207 | wordMode = false; 208 | hexMode = true; 209 | }; 210 | Action setWordMode = () => 211 | { 212 | if (dumpMode) 213 | if (hexMode && !wordMode) 214 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: Byte hex mode is mutually exclusive with word hex mode"); 215 | else if (!hexMode) 216 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: Word hex mode is mutually exclusive with ASCII mode"); 217 | dumpMode = true; 218 | wordMode = true; 219 | hexMode = true; 220 | }; 221 | Action setAsciiMode = () => 222 | { 223 | if (dumpMode) 224 | if (hexMode) 225 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: ASCII mode is mutually exclusive with hex mode"); 226 | dumpMode = true; 227 | hexMode = false; 228 | wordMode = false; 229 | }; 230 | 231 | while (curArg < args.Length) 232 | { 233 | if (args[curArg].Length != 0) 234 | { 235 | if (expectedArgs.Count() > 0) 236 | { 237 | try 238 | { 239 | switch (expectedArgs.Dequeue()) 240 | { 241 | case StringArgumentType.BaseAddress: 242 | baseAddress = Convert.ToInt32(args[curArg], 16); 243 | break; 244 | case StringArgumentType.InputFileName: 245 | inputFileName = args[curArg]; 246 | break; 247 | case StringArgumentType.OutputFileName: 248 | outputFileName = args[curArg]; 249 | break; 250 | case StringArgumentType.StartAddress: 251 | start = Convert.ToInt32(args[curArg], 16); 252 | break; 253 | case StringArgumentType.EndAddress: 254 | end = Convert.ToInt32(args[curArg], 16); 255 | break; 256 | } 257 | } 258 | catch (FormatException) 259 | { 260 | ShowShortHelp(ErrorCode.BadArgument, "Error: Invalid number " + args[curArg]); 261 | } 262 | catch (OverflowException) 263 | { 264 | ShowShortHelp(ErrorCode.BadArgument, "Error: Invalid number " + args[curArg]); 265 | } 266 | curArg++; 267 | } 268 | else if (curArg == args.Length - 1 && Regex.IsMatch(args[curArg], "^([0-9A-Fa-f]{1,6}[\\s\\r\\n\\:\\.]*:)?([\\s\\r\\n\\:\\.]*[0-9A-Fa-f][0-9A-Fa-f])+[\\s\\r\\n\\:\\.]*$")) 269 | break; 270 | else 271 | { 272 | if (args[curArg][0] == '-') 273 | { 274 | if (args[curArg].Length == 1) 275 | { 276 | ShowShortHelp(ErrorCode.BadArgument, "Error: Bare - without option character"); 277 | } 278 | if (args[curArg][1] == '-') 279 | { 280 | switch (args[curArg]) 281 | { 282 | case "--help": 283 | ShowHelp(true); 284 | break; 285 | case "--short-mode": 286 | setShortMode(); 287 | break; 288 | case "--base-address": 289 | setBaseAddress(); 290 | break; 291 | case "--eZ80": 292 | case "--ez80": 293 | case "--Ez80": // I hate you if you use these. 294 | case "--EZ80": 295 | seteZ80Mode(); 296 | break; 297 | case "--Z80": 298 | case "--z80": 299 | setZ80Mode(); 300 | break; 301 | case "--infile": 302 | setReadFile(); 303 | break; 304 | case "--binfile": 305 | setBinFile(); 306 | break; 307 | case "--no-labels": 308 | unsetShowLabels(); 309 | break; 310 | case "--stdout": 311 | setWriteStdOut(); 312 | break; 313 | case "--outfile": 314 | setWriteOutFile(); 315 | break; 316 | case "--pad-tabs": 317 | setUseTabs(); 318 | break; 319 | case "--no-align": 320 | unsetAlignArgs(); 321 | break; 322 | case "--hide-opcodes": 323 | unsetShowOpcodes(); 324 | break; 325 | case "--no-pause": 326 | unsetPause(); 327 | break; 328 | case "--pause": 329 | setPause(); 330 | break; 331 | case "--stdin": 332 | setStdIn(); 333 | break; 334 | case "--append": 335 | setAppend(); 336 | break; 337 | case "--no-append": 338 | unsetAppend(); 339 | break; 340 | case "--irc-mode": 341 | setIrcMode(); 342 | break; 343 | case "--from": 344 | setStartAddr(); 345 | break; 346 | case "--to": 347 | setEndAddr(); 348 | break; 349 | case "--show-addresses": 350 | setShowAddresses(); 351 | break; 352 | case "--hex-dump": 353 | setHexMode(); 354 | break; 355 | case "--word-dump": 356 | setWordMode(); 357 | break; 358 | case "--ascii": 359 | setAsciiMode(); 360 | break; 361 | default: 362 | ShowShortHelp(ErrorCode.BadArgument, "Error: Unrecognized option " + args[curArg]); 363 | return (int)ErrorCode.BadArgument; 364 | } 365 | } 366 | else 367 | { 368 | for (int i = 1; i < args[curArg].Length; i++) 369 | switch (args[curArg][i]) 370 | { 371 | case 'b': 372 | setBaseAddress(); 373 | break; 374 | case 'i': 375 | setReadFile(); 376 | break; 377 | case 'I': 378 | setBinFile(); 379 | break; 380 | case 'E': 381 | seteZ80Mode(); 382 | break; 383 | case 'e': 384 | setZ80Mode(); 385 | break; 386 | case 'A': 387 | setLongMode(); 388 | break; 389 | case 'a': 390 | setShortMode(); 391 | break; 392 | case 'L': 393 | setShowLabels(); 394 | break; 395 | case 'l': 396 | unsetShowLabels(); 397 | break; 398 | case 'X': 399 | setShowOpcodes(); 400 | break; 401 | case 'x': 402 | unsetShowOpcodes(); 403 | break; 404 | case 'T': 405 | setAlignArgs(); 406 | break; 407 | case 't': 408 | unsetAlignArgs(); 409 | break; 410 | case 'S': 411 | unsetUseTabs(); 412 | break; 413 | case 's': 414 | setUseTabs(); 415 | break; 416 | case 'D': 417 | unsetShowAddresses(); 418 | break; 419 | case 'd': 420 | setShowAddresses(); 421 | break; 422 | case 'P': 423 | unsetPause(); 424 | break; 425 | case 'p': 426 | setPause(); 427 | break; 428 | case 'o': 429 | setWriteOutFile(); 430 | break; 431 | case 'O': 432 | setWriteStdOut(); 433 | break; 434 | case 'c': 435 | setIrcMode(); 436 | break; 437 | case 'C': 438 | unsetIrcMode(); 439 | break; 440 | case 'n': 441 | setStdIn(); 442 | break; 443 | case 'Z': 444 | setAppend(); 445 | break; 446 | case 'z': 447 | unsetAppend(); 448 | break; 449 | case 'r': 450 | setStartAddr(); 451 | break; 452 | case 'R': 453 | setEndAddr(); 454 | break; 455 | case 'h': 456 | setHexMode(); 457 | break; 458 | case 'H': 459 | setWordMode(); 460 | break; 461 | case 'g': 462 | setAsciiMode(); 463 | break; 464 | default: 465 | ShowShortHelp(ErrorCode.BadArgument, "Error: Unrecognized option -" + args[curArg][i]); 466 | return (int)ErrorCode.BadArgument; 467 | } 468 | } 469 | } 470 | else 471 | ShowShortHelp(ErrorCode.BadArgument, "Error: Bad argument " + args[curArg]); 472 | curArg++; 473 | } 474 | } 475 | } 476 | 477 | if (expectedArgs.Count > 0) 478 | { 479 | while (expectedArgs.Count > 1) 480 | Console.Error.WriteLine("Error: Missing implied argument " + expectedArgs.Dequeue().ToString()); 481 | ShowShortHelp(ErrorCode.MissingImpliedArgument, "Error: Missing implied argument " + expectedArgs.Dequeue().ToString()); 482 | } 483 | #endregion 484 | 485 | byte[] data = new byte[] {0}; 486 | string inputText = ""; 487 | 488 | if (stdin) 489 | { 490 | StringBuilder b = new StringBuilder(); 491 | string s; 492 | while ((s = Console.ReadLine()) != null) 493 | b.Append(s); 494 | inputText = b.ToString(); 495 | } 496 | else 497 | if (readInputFile) 498 | { 499 | try 500 | { 501 | if (binaryInputFile) 502 | data = System.IO.File.ReadAllBytes(inputFileName); 503 | else 504 | inputText = System.IO.File.ReadAllText(inputFileName); 505 | } 506 | catch 507 | { 508 | ShowShortHelp(ErrorCode.FileOpenError, "Error opening input file " + inputFileName); 509 | } 510 | } 511 | else 512 | inputText = args[args.Length - 1]; 513 | 514 | if (!binaryInputFile) 515 | { 516 | Regex baseAddressPrefixRegex = new Regex("^\\s*[0-9A-Fa-f]{1,6}[\\s\\r\\n\\:\\.]*\\:"); 517 | if (baseAddressPrefixRegex.IsMatch(inputText)) 518 | { 519 | if (hasBaseAddress) 520 | ShowShortHelp(ErrorCode.ConflictingArgument, "Error: Input string has base address specifier, which conflicts with -b argument."); 521 | hasBaseAddress = true; 522 | baseAddress = Convert.ToInt32(Regex.Match(inputText, "[0-9A-Fa-f]{1,6}").Value, 16); 523 | inputText = baseAddressPrefixRegex.Replace(inputText, "", 1); 524 | } 525 | if (!Regex.IsMatch(inputText, "^([\\s\\r\\n\\:\\.]*[0-9A-Fa-f][0-9A-Fa-f])+[\\s\\r\\n\\:\\.]*$")) 526 | ShowShortHelp(ErrorCode.InvalidHexString, "Error: input is not valid hex string"); 527 | List bytes = new List(); 528 | foreach (Match m in Regex.Matches(inputText, "[0-9A-Fa-f][0-9A-Fa-f]")) 529 | bytes.Add(Convert.ToByte(m.Value, 16)); 530 | data = bytes.ToArray(); 531 | } 532 | 533 | if (end == 0) 534 | end = data.Length; 535 | else 536 | end -= baseAddress; 537 | if (end >= data.Length) 538 | end = data.Length - 1; 539 | if (haveStart) 540 | start -= baseAddress; 541 | if (start > end) 542 | ShowShortHelp(ErrorCode.BadArgument, "Error: End address cannot be before start address"); 543 | if (start < 0) 544 | ShowShortHelp(ErrorCode.BadArgument, "Error: Start address is before start of input data"); 545 | 546 | StreamsWriter writer = new StreamsWriter(); 547 | if (writeStdOut) 548 | writer.StdOutWriter = Console.Out; 549 | if (writeOutputFile) 550 | try 551 | { 552 | writer.FileWriter = new StreamWriter(outputFileName, append); 553 | } 554 | catch 555 | { 556 | ShowShortHelp(ErrorCode.FileOpenError, "Error opening output file " + outputFileName); 557 | } 558 | 559 | int addrColWidth = 8; 560 | int opcodeColWidth = 14; 561 | int instrColWidth = 8; 562 | 563 | if (!dumpMode) 564 | { 565 | eZ80Disassembler.DisassembledInstruction[] instrs = 566 | eZ80Disassembler.Disassemble(data, start, end, baseAddress, hasBaseAddress, adlMode, z80ClassicMode, addLabels ? "label_" : "", addLabels ? "loc_" : ""); 567 | 568 | HashSet knownLabels = new HashSet(); 569 | 570 | if (addLabels) 571 | foreach (eZ80Disassembler.DisassembledInstruction instr in instrs) 572 | if (instr.IsBranch) 573 | knownLabels.Add(instr.BranchTarget); 574 | 575 | for (int j = 0; j < instrs.Length; j++) 576 | { 577 | eZ80Disassembler.DisassembledInstruction instr = instrs[j]; 578 | if (addLabels && knownLabels.Contains(instr.StartPosition + baseAddress)) 579 | { 580 | if (showAddresses) 581 | if (useTabs) 582 | writer.Write("\t"); 583 | else 584 | for (int c = 0; c < addrColWidth - 2; c++) 585 | writer.Write(" "); 586 | if (showOpcodes) 587 | if (useTabs) 588 | writer.Write("\t\t"); 589 | else 590 | for (int c = 0; c < opcodeColWidth - (showAddresses ? 0 : 2) ; c++) 591 | writer.Write(" "); 592 | writer.Write("label_"); 593 | if (z80ClassicMode) 594 | writer.Write(((instr.StartPosition + baseAddress) & 0xFFFF).ToString("X4")); 595 | else 596 | writer.Write((instr.StartPosition + baseAddress).ToString("X6")); 597 | writer.Write(":"); 598 | if (!ircMode) 599 | writer.WriteLine(); 600 | else 601 | writer.Write(" "); 602 | } 603 | if (showAddresses) 604 | { 605 | if (z80ClassicMode) 606 | writer.Write((instr.StartPosition + baseAddress).ToString("X4")); 607 | else 608 | writer.Write((instr.StartPosition + baseAddress).ToString("X6")); 609 | writer.Write(":"); 610 | if (useTabs) 611 | writer.Write("\t"); 612 | else 613 | for (int c = z80ClassicMode ? 5 : 7; c < addrColWidth; c++) 614 | writer.Write(" "); 615 | } 616 | if (showOpcodes) 617 | { 618 | for (int i = 0; i < instr.Length; i++) 619 | writer.Write(data[instr.StartPosition + i].ToString("X2")); 620 | if (useTabs) 621 | { 622 | if (instr.Length <= 3) 623 | writer.Write("\t"); 624 | writer.Write("\t"); 625 | } 626 | else 627 | for (int c = 2 * instr.Length; c < opcodeColWidth; c++) 628 | writer.Write(" "); 629 | } 630 | else 631 | if (!ircMode) 632 | if (useTabs) 633 | writer.Write("\t"); 634 | else 635 | writer.Write(" "); 636 | writer.Write(instr.InstructionName); 637 | writer.Write(instr.InstructionSuffix); 638 | if (!String.IsNullOrEmpty(instr.InstructionArguments)) 639 | { 640 | if (alignArgs) 641 | if (useTabs) 642 | writer.Write("\t"); 643 | else 644 | { 645 | for (int c = instr.InstructionName.Length + instr.InstructionSuffix.Length - 1; c < instrColWidth; c++) 646 | writer.Write(" "); 647 | writer.Write(" "); 648 | } 649 | else 650 | writer.Write(" "); 651 | writer.Write(instr.InstructionArguments); 652 | } 653 | if (j != instrs.Length - 1) 654 | if (!ircMode) 655 | writer.WriteLine(); 656 | else 657 | writer.Write(" \\ "); 658 | } 659 | } 660 | else 661 | { 662 | string size = "X2"; 663 | if (wordMode) 664 | if (adlMode) 665 | size = "X6"; 666 | else 667 | size = "X4"; 668 | int num; 669 | int addr = start - 1; 670 | while (addr++ < end) 671 | { 672 | if (showAddresses) 673 | { 674 | if (z80ClassicMode) 675 | writer.Write((addr + baseAddress).ToString("X4")); 676 | else 677 | writer.Write((addr + baseAddress).ToString("X6")); 678 | writer.Write(":"); 679 | if (useTabs) 680 | writer.Write("\t"); 681 | else 682 | for (int c = z80ClassicMode ? 5 : 7; c < addrColWidth; c++) 683 | writer.Write(" "); 684 | } 685 | if (showOpcodes) 686 | { 687 | /*for (int c = ; c < opcodeColWidth; c++) 688 | writer.Write(" ");*/ 689 | } 690 | else 691 | if (!ircMode) 692 | if (useTabs) 693 | writer.Write("\t"); 694 | else 695 | writer.Write(" "); 696 | num = data[addr]; 697 | if (hexMode) 698 | { 699 | if (wordMode) 700 | { 701 | num |= data[++addr] << 8; 702 | if (adlMode) 703 | num |= data[++addr] << 16; 704 | } 705 | writer.Write(num.ToString(size)); 706 | writer.Write(", "); 707 | } 708 | else 709 | { 710 | if (num >= 0x20 && num <= 0x7E) 711 | writer.Write(((char)num).ToString()); 712 | else 713 | { 714 | writer.Write("\", "); 715 | writer.Write(num.ToString("X2")); 716 | writer.Write(", \""); 717 | } 718 | } 719 | } 720 | } 721 | 722 | if (pause) 723 | Console.ReadKey(); 724 | 725 | writer.Close(); 726 | return (int)ErrorCode.NoError; 727 | } 728 | 729 | class StreamsWriter 730 | { 731 | public StreamWriter FileWriter; 732 | public TextWriter StdOutWriter; 733 | 734 | public void Write(string str) 735 | { 736 | if (FileWriter != null) 737 | FileWriter.Write(str); 738 | if (StdOutWriter != null) 739 | StdOutWriter.Write(str); 740 | } 741 | 742 | public void WriteLine(string str) 743 | { 744 | if (FileWriter != null) 745 | FileWriter.WriteLine(str); 746 | if (StdOutWriter != null) 747 | StdOutWriter.WriteLine(str); 748 | } 749 | 750 | public void WriteLine() 751 | { 752 | if (FileWriter != null) 753 | FileWriter.WriteLine(); 754 | if (StdOutWriter != null) 755 | StdOutWriter.WriteLine(); 756 | } 757 | 758 | public void Close() 759 | { 760 | if (FileWriter != null) 761 | FileWriter.Dispose(); 762 | } 763 | } 764 | 765 | #if WIN_32 766 | static void ShowDummyHelp() 767 | { 768 | Console.WriteLine("eZDisasm, an eZ80 and classic Z80 disassembler"); 769 | Console.WriteLine(); 770 | Console.WriteLine("This is a command-line application. You must run it from the command line."); 771 | Console.WriteLine("It is not an interactive application."); 772 | Console.WriteLine("For syntaxic help:"); 773 | Console.WriteLine(" eZDisasm --help"); 774 | } 775 | #endif 776 | 777 | static void ShowShortHelp(ErrorCode e, string msg) 778 | { 779 | #if WIN_32 780 | if (newConsole && pause) 781 | { 782 | ShowDummyHelp(); 783 | Console.WriteLine(); 784 | Console.Write("Message: "); 785 | Console.Error.WriteLine(msg); 786 | Console.ReadKey(); 787 | Environment.Exit((int)e); 788 | } 789 | #endif 790 | //Console.WriteLine(msg); 791 | Console.Error.WriteLine(msg); 792 | Console.WriteLine("Usage: eZDisasm [-acdelstxOp] [-b ] [-o ] {-i/I | }"); 793 | Console.WriteLine("For help: eZDisasm --help"); 794 | #if DEBUG 795 | Console.ReadKey(); 796 | #else 797 | if (pause) 798 | Console.ReadKey(); 799 | #endif 800 | Environment.Exit((int)e); 801 | } 802 | 803 | static void ShowHelp(bool forceshow) 804 | { 805 | #if WIN_32 806 | if (!forceshow && newConsole && pause) 807 | { 808 | ShowDummyHelp(); 809 | Console.ReadKey(); 810 | Environment.Exit((int)ErrorCode.NoError); 811 | } 812 | #endif 813 | Assembly assembly = Assembly.GetExecutingAssembly(); 814 | using (Stream stream = assembly.GetManifestResourceStream("eZDisasm.readme.txt")) 815 | using (StreamReader reader = new StreamReader(stream)) 816 | Console.WriteLine(reader.ReadToEnd()); 817 | if (pause) 818 | Console.ReadKey(); 819 | Environment.Exit((int)ErrorCode.NoError); 820 | } 821 | } 822 | } 823 | -------------------------------------------------------------------------------- /eZDisasm/eZ80Disassembler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace eZDisasm 8 | { 9 | public class eZ80Disassembler 10 | { 11 | // This is based on http://www.z80.info/decoding.htm 12 | public struct DisassembledInstruction 13 | { 14 | public string InstructionName; 15 | public string InstructionArguments; 16 | public string InstructionSuffix; 17 | public int StartPosition; 18 | public byte Length; 19 | public bool IsBranch; 20 | public int BranchTarget; 21 | 22 | public string ToString(bool indentArguments = false) 23 | { 24 | if (!indentArguments) 25 | return InstructionName + InstructionSuffix 26 | + (String.IsNullOrEmpty(InstructionArguments) 27 | ? "" 28 | : " " + InstructionArguments); 29 | else 30 | return InstructionName + InstructionSuffix 31 | + (String.IsNullOrEmpty(InstructionArguments) 32 | ? "" 33 | : new String(' ', 10 - InstructionName.Length - InstructionSuffix.Length) + InstructionArguments); 34 | } 35 | } 36 | 37 | public static DisassembledInstruction[] Disassemble(byte[] data, int start, int end, int baseAddress = 0, bool hasBaseAddress = false, bool adlMode = true, bool plainZ80Mode = false, string labelPrefixString = "", string locPrefixString = "") 38 | { 39 | List disasm = new List(); 40 | eZ80Disassembler dis = new eZ80Disassembler(); 41 | dis.Data = data; 42 | dis.BaseAddress = baseAddress; 43 | if (baseAddress != 0) 44 | dis.HasBaseAddress = true; 45 | else 46 | dis.HasBaseAddress = hasBaseAddress; 47 | dis.AdlMode = adlMode; 48 | dis.Z80PlainMode = plainZ80Mode; 49 | dis.CurrentByte = start; 50 | dis.LabelPrefixString = labelPrefixString; 51 | dis.LocationPrefixString = locPrefixString; 52 | while (dis.CurrentByte <= end) 53 | disasm.Add(dis.DoDisassembleInstruction()); 54 | 55 | return disasm.ToArray(); 56 | } 57 | 58 | 59 | protected eZ80Disassembler() 60 | { 61 | 62 | } 63 | 64 | 65 | protected byte[] Data; 66 | protected int BaseAddress; 67 | protected bool HasBaseAddress; 68 | protected bool AdlMode; 69 | protected bool Z80PlainMode; 70 | protected string LabelPrefixString; 71 | protected string LocationPrefixString; 72 | protected int CurrentByte; 73 | protected DisassembledInstruction CurrentInstruction; 74 | protected AddressingModePrefix CurrentPrefix; 75 | protected bool LongData; 76 | protected string WordDataFormatString; 77 | protected static readonly string Format1Byte = "X2"; 78 | protected static readonly string Format2Byte = "X4"; 79 | protected static readonly string Format3Byte = "X6"; 80 | 81 | protected enum AddressingModePrefix 82 | { 83 | None, 84 | Sis, 85 | Sil, 86 | Lis, 87 | Lil, 88 | } 89 | 90 | 91 | protected DisassembledInstruction DoDisassembleInstruction() 92 | { 93 | CurrentPrefix = AddressingModePrefix.None; 94 | LongData = AdlMode; 95 | if (LongData) 96 | WordDataFormatString = Format3Byte; 97 | else 98 | WordDataFormatString = Format2Byte; 99 | CurrentInstruction = default(DisassembledInstruction); 100 | CurrentInstruction.InstructionName = "ERROR"; 101 | CurrentInstruction.InstructionArguments = ""; 102 | CurrentInstruction.InstructionSuffix = ""; 103 | CurrentInstruction.Length = 0; 104 | //CurrentInstruction.Disassembly = "ERROR"; 105 | CurrentInstruction.StartPosition = CurrentByte; 106 | try 107 | { 108 | DisassembleInstruction(); 109 | CurrentInstruction.Length = (byte)(CurrentByte - CurrentInstruction.StartPosition); 110 | } 111 | catch (IndexOutOfRangeException) 112 | { 113 | CurrentInstruction.InstructionName = ""; 114 | CurrentInstruction.InstructionArguments = ""; 115 | CurrentInstruction.InstructionSuffix = ""; 116 | CurrentInstruction.Length = (byte)(Data.Length - CurrentInstruction.StartPosition); 117 | } 118 | /*CurrentInstruction.Disassembly = CurrentInstruction.InstructionName + CurrentInstruction.InstructionSuffix 119 | + (String.IsNullOrEmpty(CurrentInstruction.InstructionArguments) 120 | ? "" 121 | : " " + CurrentInstruction.InstructionArguments);*/ 122 | return CurrentInstruction; 123 | } 124 | 125 | protected int ReadImmWord() 126 | { 127 | int r = Data[CurrentByte++] | (Data[CurrentByte++] << 8); 128 | if (LongData) 129 | r |= (Data[CurrentByte++] << 16); 130 | return r; 131 | } 132 | 133 | static string SignedByte(int x) 134 | { 135 | if (x >= 0) 136 | return x.ToString("X2"); 137 | else 138 | return "-" + (-x).ToString("X2"); 139 | } 140 | 141 | protected void DisassembleInstruction() 142 | { 143 | unchecked 144 | { 145 | int branchTarget; 146 | int b = Data[CurrentByte++]; 147 | // Do you like switches? 'Cause that's kind of kinky. 148 | switch (GetField(Field.x, b)) 149 | { 150 | case 0: 151 | switch (GetField(Field.z, b)) 152 | { 153 | case 0: 154 | switch (GetField(Field.y, b)) 155 | { 156 | case 0: 157 | CurrentInstruction.InstructionName = "nop"; 158 | break; 159 | case 1: 160 | CurrentInstruction.InstructionName = "ex"; 161 | CurrentInstruction.InstructionArguments = "af, af'"; 162 | break; 163 | case 2: 164 | branchTarget = (sbyte)Data[CurrentByte++]; 165 | if (HasBaseAddress) 166 | branchTarget += CurrentByte + BaseAddress; 167 | if (Z80PlainMode) 168 | branchTarget &= 0xFFFF; 169 | CurrentInstruction.IsBranch = true; 170 | CurrentInstruction.BranchTarget = branchTarget; 171 | CurrentInstruction.InstructionName = "djnz"; 172 | if (HasBaseAddress) 173 | CurrentInstruction.InstructionArguments = LabelPrefixString + branchTarget.ToString(Z80PlainMode ? Format2Byte : Format3Byte); 174 | else 175 | CurrentInstruction.InstructionArguments = SignedByte(branchTarget); 176 | break; 177 | case 3: 178 | branchTarget = (sbyte)Data[CurrentByte++]; 179 | if (HasBaseAddress) 180 | branchTarget += CurrentByte + BaseAddress; 181 | if (Z80PlainMode) 182 | branchTarget &= 0xFFFF; 183 | CurrentInstruction.IsBranch = true; 184 | CurrentInstruction.BranchTarget = branchTarget; 185 | CurrentInstruction.InstructionName = "jr"; 186 | if (HasBaseAddress) 187 | CurrentInstruction.InstructionArguments = LabelPrefixString + branchTarget.ToString(Z80PlainMode ? Format2Byte : Format3Byte); 188 | else 189 | CurrentInstruction.InstructionArguments = SignedByte(branchTarget); 190 | break; 191 | case 4: 192 | case 5: 193 | case 6: 194 | case 7: 195 | branchTarget = (sbyte)Data[CurrentByte++]; 196 | if (HasBaseAddress) 197 | branchTarget += CurrentByte + BaseAddress; 198 | if (Z80PlainMode) 199 | branchTarget &= 0xFFFF; 200 | CurrentInstruction.IsBranch = true; 201 | CurrentInstruction.BranchTarget = branchTarget; 202 | CurrentInstruction.InstructionName = "jr"; 203 | if (HasBaseAddress) 204 | CurrentInstruction.InstructionArguments = TableCC[GetField(Field.qq, b)] + ", " + LabelPrefixString + branchTarget.ToString(Z80PlainMode ? Format2Byte : Format3Byte); 205 | else 206 | CurrentInstruction.InstructionArguments = TableCC[GetField(Field.qq, b)] + ", " + SignedByte(branchTarget); 207 | break; 208 | } 209 | break; 210 | case 1: 211 | switch (GetField(Field.q, b)) 212 | { 213 | case 0: 214 | CurrentInstruction.InstructionName = "ld"; 215 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)] + ", " + ReadImmWord().ToString(WordDataFormatString); 216 | break; 217 | case 1: 218 | CurrentInstruction.InstructionName = "add"; 219 | CurrentInstruction.InstructionArguments = "hl, " + TableRP[GetField(Field.p, b)]; 220 | break; 221 | } 222 | break; 223 | case 2: 224 | switch (GetField(Field.y, b)) 225 | { 226 | case 0: 227 | CurrentInstruction.InstructionName = "ld"; 228 | CurrentInstruction.InstructionArguments = "(bc), a"; 229 | break; 230 | case 1: 231 | CurrentInstruction.InstructionName = "ld"; 232 | CurrentInstruction.InstructionArguments = "a, (bc)"; 233 | break; 234 | case 2: 235 | CurrentInstruction.InstructionName = "ld"; 236 | CurrentInstruction.InstructionArguments = "(de), a"; 237 | break; 238 | case 3: 239 | CurrentInstruction.InstructionName = "ld"; 240 | CurrentInstruction.InstructionArguments = "a, (de)"; 241 | break; 242 | case 4: 243 | CurrentInstruction.InstructionName = "ld"; 244 | CurrentInstruction.InstructionArguments = "(" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + "), hl"; 245 | break; 246 | case 5: 247 | CurrentInstruction.InstructionName = "ld"; 248 | CurrentInstruction.InstructionArguments = "hl, (" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + ")"; 249 | break; 250 | case 6: 251 | CurrentInstruction.InstructionName = "ld"; 252 | CurrentInstruction.InstructionArguments = "(" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + "), a"; 253 | break; 254 | case 7: 255 | CurrentInstruction.InstructionName = "ld"; 256 | CurrentInstruction.InstructionArguments = "a, (" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + ")"; 257 | break; 258 | } 259 | break; 260 | case 3: 261 | switch (GetField(Field.q, b)) 262 | { 263 | case 0: 264 | CurrentInstruction.InstructionName = "inc"; 265 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)]; 266 | break; 267 | case 1: 268 | CurrentInstruction.InstructionName = "dec"; 269 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)]; 270 | break; 271 | } 272 | break; 273 | case 4: 274 | CurrentInstruction.InstructionName = "inc"; 275 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)]; 276 | break; 277 | case 5: 278 | CurrentInstruction.InstructionName = "dec"; 279 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)]; 280 | break; 281 | case 6: 282 | CurrentInstruction.InstructionName = "ld"; 283 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + ", " + Data[CurrentByte++].ToString("X2"); 284 | break; 285 | case 7: 286 | switch (GetField(Field.y, b)) 287 | { 288 | case 0: 289 | CurrentInstruction.InstructionName = "rlca"; 290 | break; 291 | case 1: 292 | CurrentInstruction.InstructionName = "rrca"; 293 | break; 294 | case 2: 295 | CurrentInstruction.InstructionName = "rla"; 296 | break; 297 | case 3: 298 | CurrentInstruction.InstructionName = "rra"; 299 | break; 300 | case 4: 301 | CurrentInstruction.InstructionName = "daa"; 302 | break; 303 | case 5: 304 | CurrentInstruction.InstructionName = "cpl"; 305 | break; 306 | case 6: 307 | CurrentInstruction.InstructionName = "scf"; 308 | break; 309 | case 7: 310 | CurrentInstruction.InstructionName = "ccf"; 311 | break; 312 | } 313 | break; 314 | } 315 | break; 316 | case 1: 317 | if (!Z80PlainMode) 318 | { 319 | if (CurrentPrefix != AddressingModePrefix.None) 320 | { 321 | CurrentInstruction.InstructionName = "NONI"; 322 | // Last prefix is being ignored, but this one might matter. 323 | // So unwind CurrentByte so we can process it again. 324 | CurrentByte--; 325 | return; 326 | } 327 | if (b == 0x40) 328 | { 329 | CurrentPrefix = AddressingModePrefix.Sis; 330 | CurrentInstruction.InstructionSuffix = ".sis"; 331 | LongData = false; 332 | WordDataFormatString = Format2Byte; 333 | DisassembleInstruction(); 334 | return; 335 | } 336 | else if (b == 0x49) 337 | { 338 | CurrentPrefix = AddressingModePrefix.Sil; 339 | CurrentInstruction.InstructionSuffix = ".lis"; 340 | LongData = true; 341 | WordDataFormatString = Format2Byte; 342 | DisassembleInstruction(); 343 | return; 344 | } 345 | else if (b == 0x52) 346 | { 347 | CurrentPrefix = AddressingModePrefix.Lis; 348 | CurrentInstruction.InstructionSuffix = ".sil"; 349 | LongData = false; 350 | WordDataFormatString = Format3Byte; 351 | DisassembleInstruction(); 352 | return; 353 | } 354 | else if (b == 0x5B) 355 | { 356 | CurrentPrefix = AddressingModePrefix.Lil; 357 | CurrentInstruction.InstructionSuffix = ".lil"; 358 | LongData = true; 359 | WordDataFormatString = Format3Byte; 360 | DisassembleInstruction(); 361 | return; 362 | } 363 | } 364 | if (b == 0x76) 365 | CurrentInstruction.InstructionName = "halt"; 366 | else 367 | { 368 | CurrentInstruction.InstructionName = "ld"; 369 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + ", " + TableR[GetField(Field.z, b)]; 370 | } 371 | break; 372 | case 2: 373 | CurrentInstruction.InstructionName = TableAlu[GetField(Field.y, b)]; 374 | CurrentInstruction.InstructionArguments = TableAluArg[GetField(Field.y, b)] + TableR[GetField(Field.z, b)]; 375 | break; 376 | case 3: 377 | switch (GetField(Field.z, b)) 378 | { 379 | case 0: 380 | CurrentInstruction.InstructionName = "ret"; 381 | CurrentInstruction.InstructionArguments = TableCC[GetField(Field.y, b)]; 382 | break; 383 | case 1: 384 | switch (GetField(Field.q, b)) 385 | { 386 | case 0: 387 | CurrentInstruction.InstructionName = "pop"; 388 | CurrentInstruction.InstructionArguments = TableRP2[GetField(Field.p, b)]; 389 | break; 390 | case 1: 391 | switch (GetField(Field.p, b)) 392 | { 393 | case 0: 394 | CurrentInstruction.InstructionName = "ret"; 395 | break; 396 | case 1: 397 | CurrentInstruction.InstructionName = "exx"; 398 | break; 399 | case 2: 400 | CurrentInstruction.InstructionName = "jp"; 401 | CurrentInstruction.InstructionArguments = "(hl)"; 402 | break; 403 | case 3: 404 | CurrentInstruction.InstructionName = "ld"; 405 | CurrentInstruction.InstructionArguments = "sp, hl"; 406 | break; 407 | } 408 | break; 409 | } 410 | break; 411 | case 2: 412 | CurrentInstruction.InstructionName = "jp"; 413 | branchTarget = ReadImmWord(); 414 | CurrentInstruction.InstructionArguments = TableCC[GetField(Field.y, b)] + ", " 415 | + (branchTarget - BaseAddress >= 0 && branchTarget - BaseAddress < Data.Length ? LabelPrefixString : LabelPrefixString) 416 | + branchTarget.ToString(WordDataFormatString); 417 | CurrentInstruction.IsBranch = true; 418 | CurrentInstruction.BranchTarget = branchTarget; 419 | break; 420 | case 3: 421 | switch (GetField(Field.y, b)) 422 | { 423 | case 0: 424 | CurrentInstruction.InstructionName = "jp"; 425 | branchTarget = ReadImmWord(); 426 | CurrentInstruction.InstructionArguments = (branchTarget - BaseAddress >= 0 && branchTarget - BaseAddress < Data.Length ? LabelPrefixString : LabelPrefixString) + branchTarget.ToString(WordDataFormatString); 427 | CurrentInstruction.IsBranch = true; 428 | CurrentInstruction.BranchTarget = branchTarget; 429 | break; 430 | case 1: // CB Prefix 431 | DoCBPrefix(); 432 | break; 433 | case 2: 434 | CurrentInstruction.InstructionName = "out"; 435 | CurrentInstruction.InstructionArguments = "(" + Data[CurrentByte++].ToString("X2") + "), a"; 436 | break; 437 | case 3: 438 | CurrentInstruction.InstructionName = "in"; 439 | CurrentInstruction.InstructionArguments = "a, (" + Data[CurrentByte++].ToString("X2") + ")"; 440 | break; 441 | case 4: 442 | CurrentInstruction.InstructionName = "ex"; 443 | CurrentInstruction.InstructionArguments = "(sp), hl"; 444 | break; 445 | case 5: 446 | CurrentInstruction.InstructionName = "ex"; 447 | CurrentInstruction.InstructionArguments = "de, hl"; 448 | break; 449 | case 6: 450 | CurrentInstruction.InstructionName = "di"; 451 | break; 452 | case 7: 453 | CurrentInstruction.InstructionName = "ei"; 454 | break; 455 | } 456 | break; 457 | case 4: 458 | branchTarget = ReadImmWord(); 459 | CurrentInstruction.IsBranch = true; 460 | CurrentInstruction.BranchTarget = branchTarget; 461 | CurrentInstruction.InstructionName = "call"; 462 | CurrentInstruction.InstructionArguments = TableCC[GetField(Field.y, b)] + ", " 463 | + (branchTarget - BaseAddress >= 0 && branchTarget - BaseAddress < Data.Length ? LabelPrefixString : LabelPrefixString) 464 | + branchTarget.ToString(WordDataFormatString); 465 | break; 466 | case 5: 467 | switch (GetField(Field.q, b)) 468 | { 469 | case 0: 470 | CurrentInstruction.InstructionName = "push"; 471 | CurrentInstruction.InstructionArguments = TableRP2[GetField(Field.p, b)]; 472 | break; 473 | case 1: 474 | switch (b) 475 | { 476 | case 0xCD: 477 | branchTarget = ReadImmWord(); 478 | CurrentInstruction.IsBranch = true; 479 | CurrentInstruction.BranchTarget = branchTarget; 480 | CurrentInstruction.InstructionName = "call"; 481 | CurrentInstruction.InstructionArguments = (branchTarget - BaseAddress >= 0 && branchTarget - BaseAddress < Data.Length ? LabelPrefixString : LabelPrefixString) 482 | + branchTarget.ToString(WordDataFormatString); 483 | break; 484 | case 0xDD: 485 | DoIndexPrefix("ix", 0); 486 | break; 487 | case 0xED: 488 | DoEDPrefix(); 489 | break; 490 | case 0xFD: 491 | DoIndexPrefix("iy", 1); 492 | break; 493 | } 494 | break; 495 | } 496 | break; 497 | case 6: 498 | CurrentInstruction.InstructionName = TableAlu[GetField(Field.y, b)]; 499 | CurrentInstruction.InstructionArguments = TableAluArg[GetField(Field.y, b)] + Data[CurrentByte++].ToString("X2"); 500 | break; 501 | case 7: 502 | CurrentInstruction.InstructionName = "rst"; 503 | CurrentInstruction.InstructionArguments = (GetField(Field.y, b) * 8).ToString("X2") + "h"; 504 | break; 505 | } 506 | break; 507 | } 508 | return; 509 | } 510 | } 511 | 512 | private void DoCBPrefix() 513 | { 514 | byte b = Data[CurrentByte++]; 515 | switch (GetField(Field.x, b)) 516 | { 517 | case 0: 518 | CurrentInstruction.InstructionName = TableRot[GetField(Field.y, b)]; 519 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.z, b)]; 520 | break; 521 | case 1: 522 | CurrentInstruction.InstructionName = "bit"; 523 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", " + TableR[GetField(Field.z, b)]; 524 | break; 525 | case 2: 526 | CurrentInstruction.InstructionName = "res"; 527 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", " + TableR[GetField(Field.z, b)]; 528 | break; 529 | case 3: 530 | CurrentInstruction.InstructionName = "set"; 531 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", " + TableR[GetField(Field.z, b)]; 532 | break; 533 | } 534 | } 535 | 536 | 537 | private void DoEDPrefix() 538 | { 539 | string indexreg; 540 | string tempstr = ""; 541 | byte b = Data[CurrentByte++]; 542 | switch (GetField(Field.x, b)) 543 | { 544 | case 0: 545 | if (Z80PlainMode) 546 | { 547 | CurrentInstruction.InstructionName = "NONI \\ NOP"; 548 | return; 549 | } 550 | switch (GetField(Field.z, b)) 551 | { 552 | case 0: 553 | if (b == 0x30) 554 | { 555 | CurrentInstruction.InstructionName = "OPCODETRAP"; 556 | return; 557 | } 558 | CurrentInstruction.InstructionName = "in0"; 559 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + ", (" + Data[CurrentByte++].ToString("X2") + ")"; 560 | break; 561 | case 1: 562 | if (b == 0x31) 563 | { 564 | CurrentInstruction.InstructionName = "ld"; 565 | CurrentInstruction.InstructionArguments = "iy, (hl)"; 566 | } 567 | else 568 | { 569 | CurrentInstruction.InstructionName = "out0"; 570 | CurrentInstruction.InstructionArguments = "(" + Data[CurrentByte++].ToString("X2") + "), " + TableR[GetField(Field.y, b)]; 571 | } 572 | break; 573 | case 2: 574 | case 3: 575 | if ((b & 1) != 0) 576 | indexreg = "iy"; 577 | else 578 | indexreg = "ix"; 579 | CurrentInstruction.InstructionName = "lea"; 580 | if (GetField(Field.q, b) == 0) 581 | { 582 | switch (GetField(Field.p, b)) 583 | { 584 | case 0: 585 | tempstr = "bc"; 586 | break; 587 | case 1: 588 | tempstr = "de"; 589 | break; 590 | case 2: 591 | tempstr = "hl"; 592 | break; 593 | case 3: 594 | tempstr = indexreg; 595 | break; 596 | } 597 | CurrentInstruction.InstructionArguments = tempstr + ", " + indexreg + " + " + SignedByte((sbyte)Data[CurrentByte++]); 598 | } 599 | else 600 | CurrentInstruction.InstructionName = "OPCODETRAP"; 601 | break; 602 | case 4: 603 | CurrentInstruction.InstructionName = "tst"; 604 | CurrentInstruction.InstructionArguments = "a, " + TableR[GetField(Field.y, b)]; 605 | break; 606 | case 5: 607 | CurrentInstruction.InstructionName = "OPCODETRAP"; 608 | break; 609 | case 6: 610 | if (b == 0x3E) 611 | { 612 | CurrentInstruction.InstructionName = "ld"; 613 | CurrentInstruction.InstructionArguments = "(hl), iy"; 614 | } 615 | else 616 | CurrentInstruction.InstructionName = "OPCODETRAP"; 617 | break; 618 | case 7: 619 | CurrentInstruction.InstructionName = "ld"; 620 | switch (GetField(Field.p, b)) 621 | { 622 | case 0: 623 | tempstr = "bc"; 624 | break; 625 | case 1: 626 | tempstr = "de"; 627 | break; 628 | case 2: 629 | tempstr = "hl"; 630 | break; 631 | case 3: 632 | tempstr = "ix"; 633 | break; 634 | } 635 | switch (GetField(Field.q, b)) 636 | { 637 | case 0: 638 | CurrentInstruction.InstructionArguments = tempstr + ", (hl)"; 639 | break; 640 | case 1: 641 | CurrentInstruction.InstructionArguments = "(hl), " + tempstr; 642 | break; 643 | } 644 | break; 645 | } 646 | break; 647 | case 1: 648 | switch (GetField(Field.z, b)) 649 | { 650 | case 0: 651 | CurrentInstruction.InstructionName = "in"; 652 | if (b == 0x70) 653 | if (Z80PlainMode) 654 | CurrentInstruction.InstructionArguments = "(c)"; 655 | else 656 | CurrentInstruction.InstructionName = "OPCODETRAP"; 657 | else 658 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + (Z80PlainMode ? ", (c)" : ", (bc)"); 659 | break; 660 | case 1: 661 | CurrentInstruction.InstructionName = "out"; 662 | if (b == 0x71) 663 | if (Z80PlainMode) 664 | CurrentInstruction.InstructionArguments = "(c), 0"; 665 | else 666 | CurrentInstruction.InstructionName = "OPCODETRAP"; 667 | else 668 | CurrentInstruction.InstructionArguments = (Z80PlainMode ? "(c), " : "(bc), ") + TableR[GetField(Field.y, b)]; 669 | break; 670 | case 2: 671 | if (GetField(Field.q, b) == 0) 672 | CurrentInstruction.InstructionName = "sbc"; 673 | else 674 | CurrentInstruction.InstructionName = "adc"; 675 | CurrentInstruction.InstructionArguments = "hl, " + TableRP[GetField(Field.p, b)]; 676 | break; 677 | case 3: 678 | CurrentInstruction.InstructionName = "ld"; 679 | if (GetField(Field.q, b) == 0) 680 | CurrentInstruction.InstructionArguments = "(" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + "), " + TableRP[GetField(Field.p, b)]; 681 | else 682 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)] + ", (" + LocationPrefixString + ReadImmWord().ToString(WordDataFormatString) + ")"; 683 | break; 684 | case 4: 685 | if (Z80PlainMode) 686 | { 687 | CurrentInstruction.InstructionName = "neg"; 688 | } 689 | else 690 | { 691 | if (GetField(Field.q, b) == 0) 692 | switch (GetField(Field.p, b)) 693 | { 694 | case 0: 695 | CurrentInstruction.InstructionName = "neg"; 696 | break; 697 | case 1: 698 | CurrentInstruction.InstructionName = "lea"; 699 | CurrentInstruction.InstructionArguments = "ix, iy + " + SignedByte((sbyte)Data[CurrentByte++]); 700 | break; 701 | case 2: 702 | CurrentInstruction.InstructionName = "tst"; 703 | CurrentInstruction.InstructionArguments = "a, " + Data[CurrentByte++].ToString("X2"); 704 | break; 705 | case 3: 706 | CurrentInstruction.InstructionName = "tstio"; 707 | CurrentInstruction.InstructionArguments = Data[CurrentByte++].ToString("X2"); 708 | break; 709 | } 710 | else 711 | { 712 | CurrentInstruction.InstructionName = "mlt"; 713 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)]; 714 | } 715 | } 716 | break; 717 | case 5: 718 | if (Z80PlainMode) 719 | { 720 | if (GetField(Field.y, b) != 1) 721 | CurrentInstruction.InstructionName = "retn"; 722 | else 723 | CurrentInstruction.InstructionName = "reti"; 724 | } 725 | else 726 | { 727 | switch (GetField(Field.y, b)) 728 | { 729 | case 0: 730 | CurrentInstruction.InstructionName = "retn"; 731 | break; 732 | case 1: 733 | CurrentInstruction.InstructionName = "reti"; 734 | break; 735 | case 2: 736 | CurrentInstruction.InstructionName = "lea"; 737 | CurrentInstruction.InstructionArguments = "iy, ix + " + SignedByte((sbyte)Data[CurrentByte++]); 738 | break; 739 | case 3: 740 | case 6: 741 | CurrentInstruction.InstructionName = "OPCODETRAP"; 742 | break; 743 | case 4: 744 | CurrentInstruction.InstructionName = "pea"; 745 | CurrentInstruction.InstructionArguments = "ix + " + SignedByte((sbyte)Data[CurrentByte++]); 746 | break; 747 | case 5: 748 | CurrentInstruction.InstructionName = "ld"; 749 | CurrentInstruction.InstructionArguments = "mb, a"; 750 | break; 751 | case 7: 752 | CurrentInstruction.InstructionName = "stmix"; 753 | break; 754 | } 755 | } 756 | break; 757 | case 6: 758 | if (Z80PlainMode) 759 | { 760 | CurrentInstruction.InstructionName = "im"; 761 | CurrentInstruction.InstructionArguments = TableIM[GetField(Field.y, b)]; 762 | } 763 | else 764 | { 765 | switch (GetField(Field.y, b)) 766 | { 767 | case 0: 768 | case 2: 769 | case 3: 770 | CurrentInstruction.InstructionName = "im"; 771 | CurrentInstruction.InstructionArguments = TableIM[GetField(Field.y, b)]; 772 | break; 773 | case 1: 774 | CurrentInstruction.InstructionName = "OPCODETRAP"; 775 | break; 776 | case 4: 777 | CurrentInstruction.InstructionName = "pea"; 778 | CurrentInstruction.InstructionArguments = "iy + " + SignedByte((sbyte)Data[CurrentByte++]); 779 | break; 780 | case 5: 781 | CurrentInstruction.InstructionName = "ld"; 782 | CurrentInstruction.InstructionArguments = "a, mb"; 783 | break; 784 | case 6: 785 | CurrentInstruction.InstructionName = "slp"; 786 | break; 787 | case 7: 788 | CurrentInstruction.InstructionName = "rsmix"; 789 | break; 790 | } 791 | } 792 | break; 793 | case 7: 794 | switch (GetField(Field.y, b)) 795 | { 796 | case 0: 797 | CurrentInstruction.InstructionName = "ld"; 798 | CurrentInstruction.InstructionArguments = "i, a"; 799 | break; 800 | case 1: 801 | CurrentInstruction.InstructionName = "ld"; 802 | CurrentInstruction.InstructionArguments = "r, a"; 803 | break; 804 | case 2: 805 | CurrentInstruction.InstructionName = "ld"; 806 | CurrentInstruction.InstructionArguments = " a, i"; 807 | break; 808 | case 3: 809 | CurrentInstruction.InstructionName = "ld"; 810 | CurrentInstruction.InstructionArguments = " a, r"; 811 | break; 812 | case 4: 813 | CurrentInstruction.InstructionName = "rrd"; 814 | break; 815 | case 5: 816 | CurrentInstruction.InstructionName = "rld"; 817 | break; 818 | case 6: 819 | case 7: 820 | if (Z80PlainMode) 821 | CurrentInstruction.InstructionName = "NONI \\ NOP"; 822 | else 823 | CurrentInstruction.InstructionName = "OPCODETRAP"; 824 | break; 825 | } 826 | break; 827 | } 828 | break; 829 | case 2: 830 | case 3: 831 | switch (b) 832 | { 833 | case 0xA0: 834 | CurrentInstruction.InstructionName = "ldi"; 835 | break; 836 | case 0xA1: 837 | CurrentInstruction.InstructionName = "cpi"; 838 | break; 839 | case 0xA2: 840 | CurrentInstruction.InstructionName = "ini"; 841 | break; 842 | case 0xA3: 843 | CurrentInstruction.InstructionName = "outi"; 844 | break; 845 | case 0xA4: 846 | if (Z80PlainMode) 847 | goto default; 848 | CurrentInstruction.InstructionName = "outi2"; 849 | break; 850 | case 0xA8: 851 | CurrentInstruction.InstructionName = "ldd"; 852 | break; 853 | case 0xA9: 854 | CurrentInstruction.InstructionName = "cpd"; 855 | break; 856 | case 0xAA: 857 | CurrentInstruction.InstructionName = "ind"; 858 | break; 859 | case 0xAB: 860 | CurrentInstruction.InstructionName = "outd"; 861 | break; 862 | case 0xAC: 863 | if (Z80PlainMode) 864 | goto default; 865 | CurrentInstruction.InstructionName = "outd2"; 866 | break; 867 | case 0xB0: 868 | CurrentInstruction.InstructionName = "ldir"; 869 | break; 870 | case 0xB1: 871 | CurrentInstruction.InstructionName = "cpir"; 872 | break; 873 | case 0xB2: 874 | CurrentInstruction.InstructionName = "inir"; 875 | break; 876 | case 0xB3: 877 | CurrentInstruction.InstructionName = "otir"; 878 | break; 879 | case 0xB4: 880 | if (Z80PlainMode) 881 | goto default; 882 | CurrentInstruction.InstructionName = "oti2r"; 883 | break; 884 | case 0xB8: 885 | CurrentInstruction.InstructionName = "lddr"; 886 | break; 887 | case 0xB9: 888 | CurrentInstruction.InstructionName = "cpdr"; 889 | break; 890 | case 0xBA: 891 | CurrentInstruction.InstructionName = "indr"; 892 | break; 893 | case 0xBB: 894 | CurrentInstruction.InstructionName = "otdr"; 895 | break; 896 | case 0xBC: 897 | if (Z80PlainMode) 898 | goto default; 899 | CurrentInstruction.InstructionName = "otd2r"; 900 | break; 901 | case 0x82: 902 | if (Z80PlainMode) 903 | goto default; 904 | CurrentInstruction.InstructionName = "inim"; 905 | break; 906 | case 0x83: 907 | if (Z80PlainMode) 908 | goto default; 909 | CurrentInstruction.InstructionName = "otim"; 910 | break; 911 | case 0x84: 912 | if (Z80PlainMode) 913 | goto default; 914 | CurrentInstruction.InstructionName = "ini2"; 915 | break; 916 | case 0x8A: 917 | if (Z80PlainMode) 918 | goto default; 919 | CurrentInstruction.InstructionName = "indm"; 920 | break; 921 | case 0x8B: 922 | if (Z80PlainMode) 923 | goto default; 924 | CurrentInstruction.InstructionName = "otdm"; 925 | break; 926 | case 0x8C: 927 | if (Z80PlainMode) 928 | goto default; 929 | CurrentInstruction.InstructionName = "ind2"; 930 | break; 931 | case 0x92: 932 | if (Z80PlainMode) 933 | goto default; 934 | CurrentInstruction.InstructionName = "inimr"; 935 | break; 936 | case 0x93: 937 | if (Z80PlainMode) 938 | goto default; 939 | CurrentInstruction.InstructionName = "otimr"; 940 | break; 941 | case 0x94: 942 | if (Z80PlainMode) 943 | goto default; 944 | CurrentInstruction.InstructionName = "ini2r"; 945 | break; 946 | case 0x9A: 947 | if (Z80PlainMode) 948 | goto default; 949 | CurrentInstruction.InstructionName = "indmr"; 950 | break; 951 | case 0x9B: 952 | if (Z80PlainMode) 953 | goto default; 954 | CurrentInstruction.InstructionName = "otdmr"; 955 | break; 956 | case 0x9C: 957 | if (Z80PlainMode) 958 | goto default; 959 | CurrentInstruction.InstructionName = "ind2r"; 960 | break; 961 | case 0xC2: 962 | if (Z80PlainMode) 963 | goto default; 964 | CurrentInstruction.InstructionName = "inirx"; 965 | break; 966 | case 0xC3: 967 | if (Z80PlainMode) 968 | goto default; 969 | CurrentInstruction.InstructionName = "otirx"; 970 | break; 971 | case 0xC7: 972 | if (Z80PlainMode) 973 | goto default; 974 | CurrentInstruction.InstructionName = "ld"; 975 | CurrentInstruction.InstructionArguments = "i, hl"; 976 | break; 977 | case 0xD7: 978 | if (Z80PlainMode) 979 | goto default; 980 | CurrentInstruction.InstructionName = "ld"; 981 | CurrentInstruction.InstructionArguments = "hl, i"; 982 | break; 983 | case 0xCA: 984 | if (Z80PlainMode) 985 | goto default; 986 | CurrentInstruction.InstructionName = "indrx"; 987 | break; 988 | case 0xCB: 989 | if (Z80PlainMode) 990 | goto default; 991 | CurrentInstruction.InstructionName = "otdrx"; 992 | break; 993 | default: 994 | if (Z80PlainMode) 995 | CurrentInstruction.InstructionName = "NONI \\ NOP"; 996 | else 997 | CurrentInstruction.InstructionName = "OPCODETRAP"; 998 | break; 999 | } 1000 | break; 1001 | } 1002 | } 1003 | private void DoIndexPrefix(string indexRegister, int indexRegNumber) 1004 | { 1005 | unchecked 1006 | { 1007 | byte b = Data[CurrentByte++]; 1008 | switch (b) 1009 | { 1010 | case 0x21: 1011 | CurrentInstruction.InstructionName = "ld"; 1012 | CurrentInstruction.InstructionArguments = indexRegister + ", " + ReadImmWord().ToString(WordDataFormatString); 1013 | break; 1014 | case 0x22: 1015 | CurrentInstruction.InstructionName = "ld"; 1016 | CurrentInstruction.InstructionArguments = "(" + ReadImmWord().ToString(WordDataFormatString) + "), " + indexRegister; 1017 | break; 1018 | case 0x2A: 1019 | CurrentInstruction.InstructionName = "ld"; 1020 | CurrentInstruction.InstructionArguments = indexRegister + ", (" + ReadImmWord().ToString(WordDataFormatString) + ")"; 1021 | break; 1022 | case 0x23: 1023 | CurrentInstruction.InstructionName = "inc"; 1024 | CurrentInstruction.InstructionArguments = indexRegister; 1025 | break; 1026 | case 0x2B: 1027 | CurrentInstruction.InstructionName = "dec"; 1028 | CurrentInstruction.InstructionArguments = indexRegister; 1029 | break; 1030 | case 0x24: 1031 | CurrentInstruction.InstructionName = "inc"; 1032 | CurrentInstruction.InstructionArguments = indexRegister + "h"; 1033 | break; 1034 | case 0x2C: 1035 | CurrentInstruction.InstructionName = "inc"; 1036 | CurrentInstruction.InstructionArguments = indexRegister + "l"; 1037 | break; 1038 | case 0x34: 1039 | CurrentInstruction.InstructionName = "inc"; 1040 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1041 | break; 1042 | case 0x25: 1043 | CurrentInstruction.InstructionName = "dec"; 1044 | CurrentInstruction.InstructionArguments = indexRegister + "h"; 1045 | break; 1046 | case 0x2D: 1047 | CurrentInstruction.InstructionName = "dec"; 1048 | CurrentInstruction.InstructionArguments = indexRegister + "l"; 1049 | break; 1050 | case 0x35: 1051 | CurrentInstruction.InstructionName = "dec"; 1052 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1053 | break; 1054 | case 0x26: 1055 | CurrentInstruction.InstructionName = "ld"; 1056 | CurrentInstruction.InstructionArguments = indexRegister + "h, " + SignedByte((sbyte)Data[CurrentByte++]); 1057 | break; 1058 | case 0x2E: 1059 | CurrentInstruction.InstructionName = "ld"; 1060 | CurrentInstruction.InstructionArguments = indexRegister + "l, " + SignedByte((sbyte)Data[CurrentByte++]); 1061 | break; 1062 | case 0x36: 1063 | CurrentInstruction.InstructionName = "ld"; 1064 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + "), " + Data[CurrentByte++].ToString("X2"); 1065 | break; 1066 | case 0x09: 1067 | CurrentInstruction.InstructionName = "add"; 1068 | CurrentInstruction.InstructionArguments = indexRegister + ", bc"; 1069 | break; 1070 | case 0x19: 1071 | CurrentInstruction.InstructionName = "add"; 1072 | CurrentInstruction.InstructionArguments = indexRegister + ", de"; 1073 | break; 1074 | case 0x29: 1075 | CurrentInstruction.InstructionName = "add"; 1076 | CurrentInstruction.InstructionArguments = indexRegister + ", " + indexRegister; 1077 | break; 1078 | case 0x39: 1079 | CurrentInstruction.InstructionName = "add"; 1080 | CurrentInstruction.InstructionArguments = indexRegister + ", sp"; 1081 | break; 1082 | case 0x60: 1083 | case 0x61: 1084 | case 0x62: 1085 | case 0x63: 1086 | case 0x67: 1087 | case 0x68: 1088 | case 0x69: 1089 | case 0x6A: 1090 | case 0x6B: 1091 | case 0x6F: 1092 | CurrentInstruction.InstructionName = "ld"; 1093 | CurrentInstruction.InstructionArguments = indexRegister + TableR[GetField(Field.y, b)] + ", " + TableR[GetField(Field.z, b)]; 1094 | break; 1095 | case 0x64: 1096 | case 0x65: 1097 | case 0x6C: 1098 | case 0x6D: 1099 | CurrentInstruction.InstructionName = "ld"; 1100 | CurrentInstruction.InstructionArguments = indexRegister + TableR[GetField(Field.y, b)] + ", " + indexRegister + TableR[GetField(Field.z, b)]; 1101 | break; 1102 | case 0x70: 1103 | case 0x71: 1104 | case 0x72: 1105 | case 0x73: 1106 | case 0x74: 1107 | case 0x75: 1108 | case 0x77: 1109 | CurrentInstruction.InstructionName = "ld"; 1110 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + "), " + TableR[GetField(Field.z, b)]; 1111 | break; 1112 | case 0x44: 1113 | case 0x45: 1114 | case 0x4C: 1115 | case 0x4D: 1116 | case 0x54: 1117 | case 0x55: 1118 | case 0x5C: 1119 | case 0x5D: 1120 | case 0x7C: 1121 | case 0x7D: 1122 | CurrentInstruction.InstructionName = "ld"; 1123 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + ", " + indexRegister + TableR[GetField(Field.z, b)]; 1124 | break; 1125 | case 0x46: 1126 | case 0x4E: 1127 | case 0x56: 1128 | case 0x5E: 1129 | case 0x66: 1130 | case 0x6E: 1131 | case 0x7E: 1132 | CurrentInstruction.InstructionName = "ld"; 1133 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.y, b)] + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1134 | break; 1135 | case 0x84: 1136 | case 0x85: 1137 | case 0x8C: 1138 | case 0x8D: 1139 | case 0x94: 1140 | case 0x95: 1141 | case 0x9C: 1142 | case 0x9D: 1143 | case 0xA4: 1144 | case 0xA5: 1145 | case 0xAC: 1146 | case 0xAD: 1147 | case 0xB4: 1148 | case 0xB5: 1149 | case 0xBC: 1150 | case 0xBD: 1151 | CurrentInstruction.InstructionName = TableAlu[GetField(Field.y, b)]; 1152 | CurrentInstruction.InstructionArguments = TableAluArg[GetField(Field.y, b)] + indexRegister + TableR[GetField(Field.z, b)]; 1153 | break; 1154 | case 0x86: 1155 | case 0x8E: 1156 | case 0x96: 1157 | case 0x9E: 1158 | case 0xA6: 1159 | case 0xAE: 1160 | case 0xB6: 1161 | case 0xBE: 1162 | CurrentInstruction.InstructionName = TableAlu[GetField(Field.y, b)]; 1163 | CurrentInstruction.InstructionArguments = TableAluArg[GetField(Field.y, b)] + "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1164 | break; 1165 | case 0xE1: 1166 | CurrentInstruction.InstructionName = "pop"; 1167 | CurrentInstruction.InstructionArguments = indexRegister; 1168 | break; 1169 | case 0xE9: 1170 | CurrentInstruction.InstructionName = "jp"; 1171 | CurrentInstruction.InstructionArguments = "(" + indexRegister + ")"; 1172 | break; 1173 | case 0xE3: 1174 | CurrentInstruction.InstructionName = "ex"; 1175 | CurrentInstruction.InstructionArguments = "(sp), " + indexRegister; 1176 | break; 1177 | case 0xE5: 1178 | CurrentInstruction.InstructionName = "push"; 1179 | CurrentInstruction.InstructionArguments = indexRegister; 1180 | break; 1181 | case 0xCB: 1182 | b = Data[++CurrentByte]; 1183 | switch (GetField(Field.x, b)) 1184 | { 1185 | case 0: 1186 | CurrentInstruction.InstructionName = TableRot[GetField(Field.y, b)]; 1187 | if (GetField(Field.z, b) != 6) 1188 | if (Z80PlainMode) 1189 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.z, b)] + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1190 | else 1191 | CurrentInstruction.InstructionName = "OPCODETRAP"; 1192 | else 1193 | CurrentInstruction.InstructionArguments = TableRot[GetField(Field.y, b)] + "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1194 | break; 1195 | case 1: 1196 | CurrentInstruction.InstructionName = "bit"; 1197 | if (GetField(Field.z, b) != 6 && !Z80PlainMode) 1198 | CurrentInstruction.InstructionName = "OPCODETRAP"; 1199 | else 1200 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1201 | break; 1202 | case 2: 1203 | CurrentInstruction.InstructionName = "res"; 1204 | if (GetField(Field.z, b) != 6) 1205 | if (Z80PlainMode) 1206 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.z, b)] + ", " + GetField(Field.y, b).ToString() + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1207 | else 1208 | CurrentInstruction.InstructionName = "OPCODETRAP"; 1209 | else 1210 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1211 | break; 1212 | case 3: 1213 | CurrentInstruction.InstructionName = "set"; 1214 | if (GetField(Field.z, b) != 6) 1215 | if (Z80PlainMode) 1216 | CurrentInstruction.InstructionArguments = TableR[GetField(Field.z, b)] + ", " + GetField(Field.y, b).ToString() + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1217 | else 1218 | CurrentInstruction.InstructionName = "OPCODETRAP"; 1219 | else 1220 | CurrentInstruction.InstructionArguments = GetField(Field.y, b).ToString() + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte - 1]) + ")"; 1221 | break; 1222 | } 1223 | CurrentByte++; 1224 | break; 1225 | case 0xF9: 1226 | CurrentInstruction.InstructionName = "ld"; 1227 | CurrentInstruction.InstructionArguments = "sp, " + indexRegister; 1228 | break; 1229 | case 0x07: 1230 | case 0x17: 1231 | case 0x27: 1232 | if (Z80PlainMode) 1233 | goto default; 1234 | CurrentInstruction.InstructionName = "ld"; 1235 | CurrentInstruction.InstructionArguments = TableRP[GetField(Field.p, b)] + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1236 | break; 1237 | case 0x37: 1238 | if (Z80PlainMode) 1239 | goto default; 1240 | CurrentInstruction.InstructionName = "ld"; 1241 | CurrentInstruction.InstructionArguments = indexRegister + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1242 | break; 1243 | case 0x0F: 1244 | case 0x1F: 1245 | case 0x2F: 1246 | if (Z80PlainMode) 1247 | goto default; 1248 | CurrentInstruction.InstructionName = "ld"; 1249 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + "), " + TableRP[GetField(Field.p, b)]; 1250 | break; 1251 | case 0x3F: 1252 | if (Z80PlainMode) 1253 | goto default; 1254 | CurrentInstruction.InstructionName = "ld"; 1255 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + "), " + indexRegister; 1256 | break; 1257 | case 0x31: 1258 | if (Z80PlainMode) 1259 | goto default; 1260 | CurrentInstruction.InstructionName = "ld"; 1261 | CurrentInstruction.InstructionArguments = TableIndex[indexRegNumber ^ 1] + ", (" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + ")"; 1262 | break; 1263 | case 0x3E: 1264 | if (Z80PlainMode) 1265 | goto default; 1266 | CurrentInstruction.InstructionName = "ld"; 1267 | CurrentInstruction.InstructionArguments = "(" + indexRegister + " + " + SignedByte((sbyte)Data[CurrentByte++]) + "), " + TableIndex[indexRegNumber ^ 1]; 1268 | break; 1269 | // No case ED; index registers forbidden on ED block. 1270 | // No case DD or FD: Only last prefix matters. 1271 | default: 1272 | CurrentInstruction.InstructionName = "NONI"; 1273 | // This is an invalid prefix sequence, but invalid prefix sequences are just ignored. 1274 | // We previously incremented CurrentByte to point after this opcode, 1275 | // so we have to decrement it so we can process it again later. 1276 | CurrentByte--; 1277 | break; 1278 | } 1279 | } 1280 | } 1281 | 1282 | 1283 | 1284 | private static readonly string[] TableR = new string[] 1285 | { 1286 | "b", 1287 | "c", 1288 | "d", 1289 | "e", 1290 | "h", 1291 | "l", 1292 | "(hl)", 1293 | "a", 1294 | }; 1295 | 1296 | private static readonly string[] TableIndex = new string[] 1297 | { 1298 | "ix", 1299 | "iy", 1300 | }; 1301 | 1302 | private static readonly string[] TableRP = new string[] 1303 | { 1304 | "bc", 1305 | "de", 1306 | "hl", 1307 | "sp", 1308 | }; 1309 | 1310 | private static readonly string[] TableRP2 = new string[] 1311 | { 1312 | "bc", 1313 | "de", 1314 | "hl", 1315 | "af", 1316 | }; 1317 | 1318 | private static readonly string[] TableCC = new string[] 1319 | { 1320 | "nz", 1321 | "z", 1322 | "nc", 1323 | "c", 1324 | "po", 1325 | "pe", 1326 | "p", 1327 | "m", 1328 | }; 1329 | 1330 | private static readonly string[] TableAlu = new string[] 1331 | { 1332 | "add ", 1333 | "adc ", 1334 | "sub ", 1335 | "sbc ", 1336 | "and ", 1337 | "xor ", 1338 | "or ", 1339 | "cp ", 1340 | }; 1341 | 1342 | private static readonly string[] TableAluArg = new string[] 1343 | { 1344 | "a, ", 1345 | "a, ", 1346 | "", 1347 | "a, ", 1348 | "", 1349 | "", 1350 | "", 1351 | "", 1352 | }; 1353 | 1354 | private static readonly string[] TableRot = new string[] 1355 | { 1356 | "rlc ", 1357 | "rrc ", 1358 | "rl ", 1359 | "rr ", 1360 | "sla ", 1361 | "sra ", 1362 | "sll ", 1363 | "srl ", 1364 | }; 1365 | 1366 | private static readonly string[] TableIM = new string[] 1367 | { 1368 | "0", 1369 | "?", 1370 | "1", 1371 | "2", 1372 | "0", 1373 | "?", 1374 | "1", 1375 | "2", 1376 | }; 1377 | 1378 | 1379 | 1380 | private enum Field 1381 | { 1382 | x, 1383 | y, 1384 | z, 1385 | p, 1386 | q, 1387 | pp, 1388 | qq, 1389 | }; 1390 | 1391 | private static int GetField(Field f, int b) 1392 | { 1393 | switch (f) 1394 | { 1395 | case Field.x: 1396 | return b >> 6; 1397 | case Field.y: 1398 | return (b >> 3) & 7; 1399 | case Field.z: 1400 | return b & 7; 1401 | case Field.p: 1402 | return (b >> 4) & 3; 1403 | case Field.q: 1404 | return (b >> 3) & 1; 1405 | case Field.pp: 1406 | return (b >> 5) & 1; 1407 | case Field.qq: 1408 | return (b >> 3) & 3; 1409 | } 1410 | throw new ArgumentOutOfRangeException(); 1411 | } 1412 | 1413 | 1414 | } 1415 | } 1416 | --------------------------------------------------------------------------------