├── 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 |
--------------------------------------------------------------------------------