Initial commit.
This commit is contained in:
commit
cb38eeee09
4 changed files with 1805 additions and 0 deletions
295
Readme.txt
Normal file
295
Readme.txt
Normal file
|
@ -0,0 +1,295 @@
|
|||
------------------------------------
|
||||
DisPel v1.0
|
||||
65816/SMC Disassembler
|
||||
by James Churchill of Naruto (C)2001
|
||||
------------------------------------
|
||||
10th of July, 2001.
|
||||
|
||||
pelrun@gmail.com
|
||||
|
||||
The Problem
|
||||
-----------
|
||||
|
||||
[snip]
|
||||
|
||||
Hi, pelrun from 2011 here. I wrote this document so long ago that I don't
|
||||
think it's fair to leave my griping about the tools of the time still in
|
||||
this readme. It just boils down to one statement - what was available at
|
||||
the time had a bunch of quirks that made them difficult to use for SNES
|
||||
disassembly. So I wrote my own.
|
||||
|
||||
The Solution
|
||||
------------
|
||||
|
||||
And so I present DisPel, my own 65816 disassembler. It's not nearly as
|
||||
"full-featured" as Tracer (for instance, it's not really for use with NES
|
||||
roms), but it does everything I need it to. And since it only took a day to
|
||||
write (most of which was working on the commandline parser, not the
|
||||
disassembler itself!) I wonder why I didn't do it ages ago.
|
||||
|
||||
The v0.9 is only because I haven't done exhaustive testing to ensure the
|
||||
disassembly is correct. But every piece of code I have disassembled with it
|
||||
matched exactly with code I've disassembled in the past (which was corrected
|
||||
by hand, of course!)
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
Able to disassemble a section of a rom, or a whole bank. Or all of it :)
|
||||
Correct REP/SEP instruction handling.
|
||||
Correct bank-boundary handling.
|
||||
Automatic (but overridable) HiROM and LoROM support.
|
||||
Shadow ROM support.
|
||||
User-specifiable listing origin (see below.)
|
||||
True SNES addressing - no need to worry about LoROM-offset conversion or
|
||||
headers.
|
||||
Control-C *will* stop it!
|
||||
|
||||
|
||||
True SNES addressing
|
||||
--------------------
|
||||
|
||||
Now you no longer need to worry about converting to-from LoROM addresses to
|
||||
disassemble the code you want - just enter the SNES bank/addresses you want,
|
||||
and DisPel does the conversion automatically. The SMC header is also
|
||||
automatically ignored, unless disabled with the "-n" option.
|
||||
|
||||
And now that you can select any section of the rom to disassemble, you don't
|
||||
have to worry about a 20MB+ file containing "disassembled" graphics data,
|
||||
which is just a waste of space.
|
||||
|
||||
Addresses/banks are specified using plain hex - no $ or 0x prefixes added.
|
||||
|
||||
HiROM addressing is switched on using the "-h" option. Use inSNESt or a
|
||||
similar utility to determine whether it's needed.
|
||||
|
||||
v0.91 update: I've replaced the half-assed HiROM support with a newer half-assed
|
||||
version. Specifying HiROM addresses (bank $40-$6F and $C0-$EF) will switch HiROM on
|
||||
automatically, and HiROM listings use the correct banks now (instead of bank $00+).
|
||||
|
||||
v0.95 update: HiROM is now detected automatically. If DisPel gets it wrong, you can use
|
||||
the -h/-l options to force HiROM/LoROM modeS respectively.
|
||||
|
||||
|
||||
You can disassemble a single bank using the "-b" option.
|
||||
|
||||
e.g.
|
||||
|
||||
dispel -b 1D rom.smc
|
||||
Will disassemble from $1D8000 to $1DFFFF.
|
||||
|
||||
dispel -b 1D -h rom.smc
|
||||
Will disassemble from $1D0000 to $1DFFFF.
|
||||
|
||||
Address ranges can be specified using the "-r" option. If the end address is
|
||||
omitted, the disassembly will proceed from the supplied address to the end
|
||||
of the file.
|
||||
|
||||
e.g.
|
||||
|
||||
dispel -r 58600-79700 rom.smc
|
||||
Will disassemble the range $58600 to $79700... only the valid LoROM banks,
|
||||
of course :)
|
||||
|
||||
dispel -r 58600 rom.smc
|
||||
Will disassemble from $58600 onwards.
|
||||
|
||||
|
||||
Correct REP/SEP state parsing
|
||||
-----------------------------
|
||||
|
||||
As a byproduct of the need to maintain backward compatibility with the 6502,
|
||||
certain opcodes take either a 1-byte or a 2-byte operand. Which is used is
|
||||
dictated by processor state flags, and so is software selectable. This is a
|
||||
problem with disassembly because normally the disassembler does not know
|
||||
which version of the instruction to use. This leads to the instruction
|
||||
alignment being lost and gibberish instructions being output.
|
||||
|
||||
Tracer tried to address the problem by maintaining similar state flags, and
|
||||
updating them when an instruction that would normally alter them is
|
||||
disassembled. Unfortunately, it didn't do it correctly for all the
|
||||
instructions that are affected. DisPel however should produce a correct
|
||||
listing for a subroutine when the state is set properly at the start.
|
||||
|
||||
Since most 65816 code I've seen explicitly sets the size flags at the
|
||||
beginning of each subroutine, you needn't worry about it a lot of the time.
|
||||
However, if you are disassembling a small block where the flags are set
|
||||
differently at the beginning, you can affect the initial state of the flags
|
||||
using the "-a" and "-x" options.
|
||||
|
||||
"-a" forces 8-bit accumulator mode.
|
||||
"-x" forces 8-bit X/Y register mode.
|
||||
|
||||
DisPel defaults to 16-bit accumulator and X/Y register mode.
|
||||
|
||||
Of course, this only applies at the beginning of the listing. Subsequent REP
|
||||
and SEP commands will alter the states appropriately.
|
||||
|
||||
|
||||
Bank-boundary handling
|
||||
----------------------
|
||||
|
||||
SNES code doesn't run across bank boundaries. It might in a HiROM (though
|
||||
I doubt it), but never ever in a LoROM image. So the disassembler shouldn't
|
||||
place instructions that straddle the bank boundary. If that happens, then the
|
||||
instruction alignment is definitely compromised, as one or more bytes are
|
||||
"eaten" at the start of the next bank that shouldn't be. This results in an
|
||||
incorrect listing at the start of the bank, which continues until the
|
||||
disassembler (through pure luck) re-establishes the alignment.
|
||||
|
||||
This was of great concern in Tracer, which had woeful support for
|
||||
disassembling sections of a ROM. If it didn't get it right (and you were
|
||||
bound to have some banks that started like this) then replacing them with
|
||||
a correct listing was a real pain.
|
||||
|
||||
So in DisPel I enforced the bank boundaries. If an disassembled instruction
|
||||
would go over a boundary then it is ignored. The surplus bytes up to the
|
||||
boundary are displayed without an accompanying instruction, and disassembly
|
||||
continues at the boundary onwards.
|
||||
|
||||
Just in case I'm completely wrong about the boundary-crossing on HiROMs, you
|
||||
can disable the enforcement using the -d option. But I suggest leaving it on
|
||||
to start with.
|
||||
|
||||
Shadow ROM support
|
||||
------------------
|
||||
|
||||
Shadow ROM is a feature of the SNES hardware - the entire rom image is
|
||||
mirrored at bank 80 onwards. When game code executes in those banks the
|
||||
hardware runs at a higher clock-rate than when it's running at the lower
|
||||
copy. (I think it's called FastROM and SlowROM in other documentation - for
|
||||
obvious reasons. Note I'm not talking about Fast/SlowROM *protection* here.)
|
||||
|
||||
65816 code is largely relocatable. However, long absolute addressing modes
|
||||
mean that most code *must* be run where it was assembled to run - it's
|
||||
origin. Therefore FastROM code won't work properly if attempted to be
|
||||
executed in the SlowROM banks and vice versa. Unfortunately, when you
|
||||
disassemble FastROM game code with the other tools, you get a listing based
|
||||
in the SlowROM banks, which gives you a very inconsistent view of the code -
|
||||
relative addresses point at expected places, but long jumps and the like all
|
||||
go somewhere completely unexpected!
|
||||
|
||||
If you know what's going on, there's no problem. But it's still a hassle to
|
||||
have to worry about it. Therefore DisPel has the ability to produce a listing
|
||||
using the FastROM addresses. You'll know if you need it if you see JMP's
|
||||
going to addresses above $800000.
|
||||
|
||||
For HiROMs, the SlowROM code begins at bank $40, and the FastROM copy at $C0.
|
||||
|
||||
To turn it on, either specify the address range/bank in the $80xxxx+ area
|
||||
directly, or use the -s option to convert the specified addresses to FastROM
|
||||
ones.
|
||||
|
||||
v0.95 update: FastROM is detected automatically. You can force enable/disable it
|
||||
by using the -s and -i options.
|
||||
|
||||
e.g.
|
||||
|
||||
dispel -bank 02 -s rom.smc
|
||||
Will disassemble bank 02 as bank 82.
|
||||
|
||||
dispel -bank 82 rom.smc
|
||||
Identical to above.
|
||||
|
||||
dispel -r 20000-2FFFF -s rom.smc
|
||||
Will disassemble the region $20000-$2FFFF as $820000-$82FFFF.
|
||||
|
||||
dispel -r 820000-82FFFF rom.smc
|
||||
Same as above.
|
||||
|
||||
|
||||
User-specified origin support
|
||||
-----------------------------
|
||||
|
||||
This is what I first meant to use to implement Shadow ROM support. I did it
|
||||
better above, but I decided to leave this in in case someone might find it
|
||||
useful.
|
||||
|
||||
Not all SNES code is run where it is in the rom. Some of it is copied
|
||||
elsewhere then executed at the new location (the sound code does this, but
|
||||
that's a different discussion.) Such won't work at it's original location -
|
||||
the code is assembled to run somewhere else, and all absolute addresses will
|
||||
point to incorrect places. If you ever encounter something like this, the
|
||||
"-g" option will force DisPel to assume the code is assembled somewhere other
|
||||
than it's actual location. Relatively addressed operands will be altered to
|
||||
fit.
|
||||
|
||||
You shouldn't need this. If you do, you'll probably understand what this
|
||||
does anyway. Otherwise, don't worry about it.
|
||||
|
||||
e.g.
|
||||
|
||||
dispel -b 0 -g 30000 rom.smc
|
||||
|
||||
Disassemble LoROM bank 0 ($8000-$FFFF) as if it was really at $30000-$37FFF.
|
||||
|
||||
|
||||
Miscellaneous
|
||||
-------------
|
||||
|
||||
You can output only the instructions (no address/hexdump fields) using the -t option.
|
||||
|
||||
You can also place blank lines after RTS,RTI,RTL instructions using the -p option.
|
||||
This will help show where the subroutines start/end in the code.
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
dispel [-n] [-h] [-s] [-a] [-x] [-d]
|
||||
[-b <bank>|-r <startaddr>-<endaddr>] [-g <origin>]
|
||||
[-o <outfile>] <infile>
|
||||
|
||||
Options: (numbers are hex-only, no prefixes)
|
||||
-n Don't skip SMC header
|
||||
-h HiROM memory mapping. Default is LoROM.
|
||||
-s Use shadow ROM addresses (see above.)
|
||||
-a Start in 8-bit accumulator mode. Default is 16-bit.
|
||||
-x Start in 8-bit X/Y mode. Default is 16-bit.
|
||||
-d Turn off bank-boundary enforcement (see above.)
|
||||
-b <bank> Disassemble bank <bank> only. Overrides -r.
|
||||
-r <start>-<end> Disassemble block from <start> to <end>.
|
||||
Omit -<end> to disassemble to end of file.
|
||||
-g <origin> Set origin of disassembled code (see above.)
|
||||
-o <outfile> Set file to redirect output to. Default is to the screen.
|
||||
<infile> File to disassemble.
|
||||
|
||||
|
||||
Release history
|
||||
---------------
|
||||
|
||||
v1.0001 - 5/4/2011
|
||||
No code changes; put the source into roughly the code style I use nowadays
|
||||
before making the source public, and changed from a VC5 project to GCC/Make.
|
||||
|
||||
v1.00 - 10/7/2002
|
||||
Fixed a stupid bug that made DisPel crash if the input file didn't exist.
|
||||
Lowercased the mnemonics.
|
||||
Changed the parameter format for BRK and COP
|
||||
|
||||
|
||||
|
||||
v0.99 - 10/7/2001
|
||||
Fixed a couple of errors that prevented the 8-bit register options from working,
|
||||
as well as the shadow/hirom support.
|
||||
Also fixed a small error in this document; -b overrides -r, not -a.
|
||||
|
||||
v0.96 - 3/2/2001
|
||||
Turns out I was erroneously outputting ",X" for the
|
||||
"Direct Page Indirect Indexed, Y" and
|
||||
"Direct Page Indirect Long Indexed, Y" opcodes.
|
||||
That's 16 opcodes with incorrect output - Ouch.
|
||||
Thanks to Skeud for pointing it out.
|
||||
|
||||
v0.95 - 19/11/2000
|
||||
Autodetects HiROM/LoROM and FastROM/SlowROM modes.
|
||||
Added option to put blank lines after RTS,RTL,RTI instructions
|
||||
Added option to output raw assembly (minus address/hex data fields)
|
||||
|
||||
v0.91 - 25/09/2000
|
||||
Fixed HiROM addressing to start from bank $40 instead of $00.
|
||||
Serves me right for not looking up the HiROM docs...
|
||||
|
||||
v0.9 - 24/09/2000
|
||||
Initial Release
|
7
dispel.h
Normal file
7
dispel.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
/* dispel.h
|
||||
* Header file for DisPel
|
||||
* James Churchill
|
||||
* Created 240900
|
||||
*/
|
||||
|
||||
int disasm(unsigned char *mem, unsigned long pos, unsigned char *flag, char *inst, unsigned char tsrc);
|
492
main.c
Normal file
492
main.c
Normal file
|
@ -0,0 +1,492 @@
|
|||
/* main.c
|
||||
* DisPel 65816 Disassembler
|
||||
* James Churchill
|
||||
* Created 20000924
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <io.h>
|
||||
|
||||
#include "dispel.h"
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("\nDisPel v0.99 by James Churchill of Naruto (C)2001\n"
|
||||
"65816/SMC Disassembler\n"
|
||||
"Usage: dispel [-n] [-t] [-h] [-l] [-s] [-i] [-a] [-x] [-e] [-p]\n"
|
||||
" [-b <bank>|-r <startaddr>-<endaddr>] [-g <origin>]\n"
|
||||
" [-d <width>] [-o <outfile>] <infile>\n\n"
|
||||
"Options: (numbers are hex-only, no prefixes)\n"
|
||||
" -n Don't skip SMC header\n"
|
||||
" -t Don't output addresses/hex dump.\n"
|
||||
" -h/-l Force HiROM/LoROM memory mapping.\n"
|
||||
" -s/-i Force enable/disable shadow ROM addresses (see readme.)\n"
|
||||
" -a Start in 8-bit accumulator mode. Default is 16-bit.\n"
|
||||
" -x Start in 8-bit X/Y mode. Default is 16-bit.\n"
|
||||
" -e Turn off bank-boundary enforcement. (see readme.)\n"
|
||||
" -p Split subroutines by placing blank lines after RTS,RTL,RTI\n"
|
||||
" -b <bank> Disassemble bank <bank> only. Overrides -r.\n"
|
||||
" -r <start>-<end> Disassemble block from <start> to <end>.\n"
|
||||
" Omit -<end> to disassemble to end of file.\n"
|
||||
" -g <origin> Set origin of disassembled code (see readme.)\n"
|
||||
" -d <width> No disassembly - produce a hexdump with <width> bytes/line.\n"
|
||||
" -o <outfile> Set file to redirect output to. Default is stdout.\n"
|
||||
" <infile> File to disassemble.\n");
|
||||
}
|
||||
|
||||
/* Snes9x Hi/LoROM autodetect code */
|
||||
|
||||
int AllASCII(unsigned char *b, int size)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < size; i++)
|
||||
{
|
||||
if (b[i] < 32 || b[i] > 126)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScoreHiROM(unsigned char *data)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
if ((data[0xFFDC] + data[0xFFDD]*256 + data[0xFFDE] + data[0xFFDF]*256) == 0xFFFF)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
|
||||
if (data[0xFFDA] == 0x33)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
if ((data[0xFFD5] & 0xf) < 4)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
if (!(data[0xFFFD] & 0x80))
|
||||
{
|
||||
score -= 4;
|
||||
}
|
||||
if ((1 << (data[0xFFD7] - 7)) > 48)
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
if (!AllASCII(&data[0xFFB0], 6))
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
if (!AllASCII(&data[0xFFC0], 20))
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
|
||||
return (score);
|
||||
}
|
||||
|
||||
int ScoreLoROM(unsigned char *data)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
if ((data[0x7FDC] + data[0x7FDD]*256 + data[0x7FDE] + data[0x7FDF]*256) == 0xFFFF)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
if (data[0x7FDA] == 0x33)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
if ((data[0x7FD5] & 0xf) < 4)
|
||||
{
|
||||
score += 2;
|
||||
}
|
||||
if (!(data[0x7FFD] & 0x80))
|
||||
{
|
||||
score -= 4;
|
||||
}
|
||||
if ((1 << (data[0x7FD7] - 7)) > 48)
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
if (!AllASCII(&data[0x7FB0], 6))
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
if (!AllASCII(&data[0x7FC0], 20))
|
||||
{
|
||||
score -= 1;
|
||||
}
|
||||
|
||||
return (score);
|
||||
}
|
||||
|
||||
int hexdump(unsigned char *data,unsigned long pos,unsigned long rpos,
|
||||
unsigned long len,char *inst, unsigned char dwidth)
|
||||
{
|
||||
int i;
|
||||
|
||||
sprintf(inst, "%02lX/%04lX:\t", (pos >> 16) & 0xFF, pos & 0xFFFF);
|
||||
for(i=0; i<dwidth && i+rpos<len; i++)
|
||||
{
|
||||
sprintf(inst + i*2 + 9, "%02X", data[rpos+i]);
|
||||
}
|
||||
return dwidth;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
FILE *fin,*fout;
|
||||
char infile[BUFSIZ],outfile[BUFSIZ],inst[521];
|
||||
unsigned char dmem[4],flag=0,*data;
|
||||
unsigned long len,pos=0,origin=0x1000000,start=0,end=0,rpos;
|
||||
unsigned char opt,skip=1,hirom=2,shadow=2,bound=1,tsrc=0;
|
||||
unsigned int offset,bank=0x100,i,tmp,dwidth=0;
|
||||
int hiscore,loscore;
|
||||
|
||||
outfile[0]=0;
|
||||
|
||||
// Parse the commandline
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (i=1; i<(argc-1); i++)
|
||||
{
|
||||
if (sscanf(argv[i], "-%c", &opt) == 0)
|
||||
{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
switch(opt)
|
||||
{
|
||||
case 'n':
|
||||
skip = 0;
|
||||
break;
|
||||
case 't':
|
||||
tsrc |= 1;
|
||||
break;
|
||||
case 'h':
|
||||
hirom = 1;
|
||||
break;
|
||||
case 'l':
|
||||
hirom = 0;
|
||||
break;
|
||||
case 's':
|
||||
shadow = 1;
|
||||
break;
|
||||
case 'i':
|
||||
shadow = 0;
|
||||
break;
|
||||
case 'a':
|
||||
flag |= 0x20;
|
||||
break;
|
||||
case 'x':
|
||||
flag |= 0x10;
|
||||
break;
|
||||
case 'e':
|
||||
bound = 0;
|
||||
break;
|
||||
case 'p':
|
||||
tsrc |= 2;
|
||||
break;
|
||||
case 'd':
|
||||
i++;
|
||||
if ((sscanf(argv[i], "%2X", &dwidth) == 0) || dwidth==0)
|
||||
{
|
||||
usage();
|
||||
printf("\n-d requires a hex value between 01 and FF after it.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'b':
|
||||
i++;
|
||||
if (sscanf(argv[i], "%2X", &bank) == 0)
|
||||
{
|
||||
usage();
|
||||
printf("\n-b requires a 1-byte hex value after it.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
i++;
|
||||
if (sscanf(argv[i], "%6lX-%6lX", &start, &end) == 0)
|
||||
{
|
||||
usage();
|
||||
printf("\n-a requires at least one hex value after it.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
i++;
|
||||
if (sscanf(argv[i], "%6lX", &origin) == 0)
|
||||
{
|
||||
usage();
|
||||
printf("\n-r requires one hex value after it.\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
i++;
|
||||
strcpy(outfile, argv[i]);
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
printf("\nUnknown option: -%c\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the input filename and open it
|
||||
strcpy(infile, argv[i]);
|
||||
fin = fopen(infile, "rb");
|
||||
if (!fin)
|
||||
{
|
||||
printf("Cannot open %s for reading.\n", infile);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Set up the output
|
||||
if (outfile[0] == 0)
|
||||
{
|
||||
strcpy(outfile,"STDOUT");
|
||||
fout = stdout;
|
||||
}
|
||||
else
|
||||
{
|
||||
fout = fopen(outfile, "w");
|
||||
if (!fout)
|
||||
{
|
||||
printf("Cannot open %s for writing.\n",outfile);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Read the file into memory
|
||||
len = filelength(fileno(fin));
|
||||
|
||||
// Make sure the image is big enough
|
||||
|
||||
if (len < 0x10000 || (skip == 1 && len < 0x10200))
|
||||
{
|
||||
printf("This file looks too small to be a rom image.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Allocate mem for file. Extra 3 bytes to prevent segfault during memcpy
|
||||
if ((data = malloc(len+3)) == NULL)
|
||||
{
|
||||
printf("Cant alloc %ld bytes.\n", len+3);
|
||||
exit(1);
|
||||
}
|
||||
if (skip)
|
||||
{
|
||||
len -= 0x200;
|
||||
fread(data, 0x200, 1, fin);
|
||||
}
|
||||
|
||||
fread(data, len, 1, fin);
|
||||
fclose(fin);
|
||||
|
||||
// Autodetect the HiROM/LoROM state
|
||||
|
||||
if (hirom==2)
|
||||
{
|
||||
hiscore = ScoreHiROM(data);
|
||||
loscore = ScoreLoROM(data);
|
||||
if (hiscore>loscore)
|
||||
{
|
||||
// fprintf(stderr,"Autodetected HiROM image.\n");
|
||||
hirom = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// fprintf(stderr,"Autodetected LoROM image.\n");
|
||||
hirom = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmangle the address options
|
||||
|
||||
pos = start;
|
||||
|
||||
// If shadow addresses given, convert to unshadowed and set shadow on.
|
||||
if ((bank == 0x100 && start & 0x800000) | (bank & 0x80))
|
||||
{
|
||||
shadow = 1;
|
||||
}
|
||||
|
||||
// If HiROM addresses given, convert to normal and set hirom on.
|
||||
if ((bank == 0x100 && start & 0x400000) | (bank & 0x40))
|
||||
{
|
||||
hirom=1;
|
||||
}
|
||||
bank &= 0x13F;
|
||||
start &= 0x3FFFFF;
|
||||
end &= 0x3FFFFF;
|
||||
|
||||
// Autodetect shadow
|
||||
|
||||
if(shadow == 2)
|
||||
{
|
||||
// fprintf(stderr,"%02X\n",data[hirom?0xFFD5:0x7FD5]);
|
||||
if(data[hirom?0xFFD5:0x7FD5] & 0x30)
|
||||
{
|
||||
shadow=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
shadow=0;
|
||||
}
|
||||
}
|
||||
|
||||
// If the bank byte is set, apply it to the address range
|
||||
if (bank < 0x100)
|
||||
{
|
||||
if(hirom)
|
||||
{
|
||||
pos = bank << 16;
|
||||
start = pos;
|
||||
end = start | 0xFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (bank << 16) + 0x8000;
|
||||
start = bank * 0x8000;
|
||||
end = start + 0x7FFF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!hirom)
|
||||
{
|
||||
// Convert the addresses to offsets
|
||||
if ((start & 0xFFFF) < 0x8000)
|
||||
{
|
||||
start += 0x8000;
|
||||
}
|
||||
pos = start;
|
||||
start = ((start >> 16) & 0xFF) * 0x8000 + (start & 0x7FFF);
|
||||
end = ((end >> 16) & 0xFF) * 0x8000 + (end & 0x7FFF);
|
||||
}
|
||||
}
|
||||
|
||||
// If end isn't after start, set end to end-of-file.
|
||||
if(end <= start)
|
||||
{
|
||||
end = len-1;
|
||||
}
|
||||
|
||||
// If new origin set, apply it.
|
||||
if (origin<0x1000000)
|
||||
{
|
||||
pos=origin;
|
||||
}
|
||||
|
||||
// If shadow set, apply it
|
||||
if (shadow)
|
||||
{
|
||||
pos |= 0x800000;
|
||||
}
|
||||
|
||||
// If hirom, apply the mapping
|
||||
if (hirom)
|
||||
{
|
||||
pos |= 0x400000;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
fprintf(stderr,"Start: $%06X End: $%06X Pos: $%06X\n", start, end, pos);
|
||||
fprintf(stderr,"Input: %s\nOutput: %s\n", infile, outfile);
|
||||
if(shadow)
|
||||
{
|
||||
fprintf(stderr,"Autodetected FastROM.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"Autodetected SlowROM.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Begin disassembly
|
||||
|
||||
rpos = start;
|
||||
|
||||
while (rpos < len && rpos <= end)
|
||||
{
|
||||
// copy some data to the staging area
|
||||
memcpy(dmem, data+rpos, 4);
|
||||
|
||||
// disassemble one instruction, or produce one line of hexdump
|
||||
if (dwidth == 0)
|
||||
{
|
||||
offset = disasm(dmem, pos, &flag, inst, tsrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = hexdump(data, pos, rpos, len, inst, dwidth);
|
||||
}
|
||||
|
||||
// Check for a file/block overrun
|
||||
if ((rpos + offset) > len || (rpos + offset) > (end+1))
|
||||
{
|
||||
// print out remaining bytes and finish
|
||||
fprintf(fout,"%02lX/%04lX:\t", (pos >> 16) & 0xFF, pos & 0xFFFF);
|
||||
for (i=rpos; i<len && i<=end; i++)
|
||||
{
|
||||
fprintf(fout,"%02X", data[rpos]);
|
||||
}
|
||||
fprintf(fout,"\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for a bank overrun
|
||||
if (bound && ((pos & 0xFFFF) + offset) > 0x10000)
|
||||
{
|
||||
// print out remaining bytes
|
||||
fprintf(fout, "%02lX/%04lX:\t",(pos >> 16) & 0xFF, pos & 0xFFFF);
|
||||
tmp = 0x10000 - (pos & 0xFFFF);
|
||||
for (i=0; i<tmp; i++)
|
||||
{
|
||||
fprintf(fout, "%02X", data[rpos+i]);
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
// Move to next bank
|
||||
if(!hirom)
|
||||
{
|
||||
pos = (pos & 0xFF0000) + 0x18000;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += tmp;
|
||||
}
|
||||
rpos += tmp;
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(fout, "%s\n", inst);
|
||||
|
||||
// Move to next instruction
|
||||
if (!hirom && ((pos & 0xFFFF) + offset) > 0xFFFF)
|
||||
{
|
||||
pos = (pos & 0xFF0000) + 0x18000;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos += offset;
|
||||
}
|
||||
rpos+=offset;
|
||||
}
|
||||
|
||||
fclose(fout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in a new issue