DISASM6 v1.5 - Nes oriented disassembler producing asm6 code

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Thanks, I'll assume that is the case and RE the code accordingly.

If I was a bit more knowledgeable, I could change the code myself; I'd like to see the JMP shown properly, with the "Suspected Data" comment as, well , as comment, referencing the suspect address.

But thanks to frantik for the original, anyway, I'm having fun with it!

C
charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Hi again all,
Still playing with Disasm6, but having a bit of trouble getting the custom label thingy to work. This last piece of help would be appreciated.

Here is my command line, using the "l" (labels) command:
disasm6 code7.nes -lcode7.lbl -c -r

Here is my one-line custom label file, made with Notepad:
VBlank = $c014

Yet, the asm output is still:
__c014: lda PPUSTATUS ; $c014: ad 02 20

What do I need to do to get the label to work? [I took the format of the label file from a post here on the board (sorry, don't recall where), in which someone had a similar label question and posted an image file showing his label file, so I used that format.]

I've tried numerous label file formats, with and without "$", using "0x", using "h", including and excluding the "__". What am I missing? I've even tried decimal 49172.

Thanks
Charlie
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by koitsu »

charliee1151 wrote:...

Here is my command line, using the "l" (labels) command:
disasm6 code7.nes -lcode7.lbl -c -r

Here is my one-line custom label file, made with Notepad:
VBlank = $c014

Yet, the asm output is still:
__c014: lda PPUSTATUS ; $c014: ad 02 20

What do I need to do to get the label to work?
The source code to disasm6 is provided (it's in PHP). So let's look at it, shall we? Sadly this source code is not on GitHub or anywhere I can find other than nesdev, so I have to copy-paste it here directly. First, we find that the usage syntax is:

Code: Select all

   echo <<<ENDOFSTRING
Usage:

disasm6 <file> [-t <file>] [-o #] [-l <file>] [-cdl <file>] [-cdlo #] [-d] [-i]
         [-h] [-c] [-p #] [-r] [-lc] [-uc] [-fs #] [-cs #] [-fe #] [-ce <#>] 
         [-len #] [-iw] [-m2]
That means disasm6 -l filename not disasm6 -lfilename. You choosing to exclude the space is a bad habit. Not all argv parsers are going to be able to handle that properly; maybe you wanted -l -f -i shorthand as -lfi for example. See my point? So going forward, comply with the usage syntax. This may or may not be your problem; let's assume it isn't and continue on.

Code: Select all

$labelFile = false;
...
// check command line params
for ($i = 2; $i < $argc; $i++)
{
   $nextParam = false;

   if (isset($argv[$i + 1]) && substr($argv[$i + 1],0,1) != '-')
   {  $nextParam = $argv[$i + 1];
   }

   switch (strtolower($argv[$i]))
   {
...
      case '-l':
      case '-labels':
         if (!$nextParam || !file_exists($nextParam))
         {  outputHelp("You must specify a valid file");
         }

         $labelFile = $argv[++$i];
      break;
Okay, so we can see here that $labelFile is probably getting set to the filename passed as an argument. So what uses this variable?

Code: Select all

$labelLen = 0;
if ($labelFile !== false)
{
   $fileLabels = readLabels($labelFile);
   
   //$mapperArr = $fileLabels['mapperArr'];
   //unset($fileLabels['mapperArr']);
   
   $labelLen = $fileLabels['maxLength'] - 10;
   $labelLen = $labelLen < 0 ? 0: $labelLen;
   unset ($fileLabels['maxLength']);

   $initLabels += $fileLabels;

}
Okay, so from this we can see that readLabels() is what ideally does the parsing of the file. Let's look at that.

Code: Select all

function readLabels($filename)
{

   $arr = readLabelText(file_get_contents($filename));
   
	return $arr;
	

}
Deeper into the rabbit hole we go, and more abstraction for no justified reason, hooray! The only thing that uses readLabelText() is readLabels(). It's also fantastically super awesomely amazing that the way this works is by passing the ENTIRE FILE CONTENTS as an argument, rather than just handing it a file handle or reference! *cough* So, let's look at that function...

Code: Select all

function readLabelText($str)
{
   $arr = array();
   $len = 0;
   $str  = preg_replace('%;.*$%m', '', $str);
   
   if (preg_match_all('%^\s*([a-zA-Z0-9_\-\+\@]*)\s*\=\s*([\$\%]*)([a-fA-F0-9]*)%m', $str, $matches))
   {
      foreach($matches[0] as $n => $v)
      {  $matches[1][$n] = trim($matches[1][$n]);

         $thislen = strlen($matches[1][$n]);

         if ($thislen > $len)
         {
            $len = $thislen;
         }

         if (strlen($matches[1][$n]) > 0)
         {
            if ($matches[2][$n] == '')
            {  $matches[3][$n] = dechex_pad($matches[3][$n]);
            }

            if ($matches[2][$n] == '%')
            {
               $matches[3][$n] = dechex_pad(bindec($matches[3][$n]));
            }

            $arr[strtolower($matches[3][$n])] =  $matches[1][$n];
         }
      }
   }

   $arr['maxLength'] = $len;

   return $arr;
}
Now we're into it. The first thing you can see is how there's absolutely no error checking or emission of errors -- if your label file doesn't match the preg_match_all(), then it silently says nothing. Very user-friendly!

The $str = preg_replace('%;.*$%m', '', $str); essentially deletes/ignore any lines that start with ; (i.e. comments). The author chose to use % as the delimiter instead of /.

The if (preg_match_all('%^\s*([a-zA-Z0-9_\-\+\@]*)\s*\=\s*([\$\%]*)([a-fA-F0-9]*)%m', $str, $matches)) is what does the "line matching". It's a very long regex, so let's try to turn it into an English sentence:

* ^ -- anchor at beginning of the line
* \s* -- zero or more spaces
* ([a-zA-Z0-9_\-\+\@]*) -- zero or more characters in the ranges a-z, A-Z, 0-9, underscore, hyphen, plus, or at-symbol -- and if matched, save the contents into array (not string!) $matches[0]
* \s* -- zero or more spaces
* = -- an equals sign
* \s* -- zero or more spaces
* ([\$\%]*) -- zero or more characters of dollar-sign or percentage -- and if matched, save the contents into array $matches[1]
* ([a-fA-F0-9]*) -- zero or more characters in the ranges a-f, A-F, or 0-9 (i.e. valid hexadecimal values in upper or lowercase) -- and if matched, save the contents into array $matches[2]

So based on this, the following label assignments should be 100% valid:

Code: Select all

mylabel = $abc0
otherlabel = 12345
In this case, $matches[0][0] would contain mylabel, $matches[1][0] would contain $ (address base designation, hex in this case), and $matches[2][0] would contain abc0.

I have no idea why there's a special case for % (percentange) as a unit. Maybe binary? I don't know as of right now.

The code then iterates over all the entries in $matches[0], assigning the key to $n and the value to $v.

It then issues trim() on each correlating entry in $matches[1][$n] (trims off newlines, carriage returns, and spaces from start and end of the address base designation) and stores it back into $matches[1][$n]

It then checks the length of the string of $matches[1][$n] and if it's greater than $len (which starts at 0), then it assigns $len to the length of the string. I guess this is some kind of "max string length" test scenario, though I'm not sure why (it looks like it all gets used later on in some magic key called maxLength in the $arr array. Anyway...)

It then explicitly checks for the length of the string $matches[1][$n] to be greater than 0 (probably as a safety net due to crappy parsing ;-) ). If true:

It then compares $matches[2][$n] to '' (an empty string). If it's true, it uses dechex_pad() to turn -- I'm guessing here -- a decimal value in $matches[3][$n] into something. I haven't looked at dechex_pad() yet. It stores the result back in $matches[3][$n]. This is a new key/array entry in $matches.

It then compares $matches[2][$n] to '$' (dollar sign). If it's true, it uses dechex_pad(bindec()) to turn -- again, guessing -- a hexadecimal value in $matches[3][$n] into something. It stores the result back in $matches[3][$n]. This is a new key/array entry in $matches.

Finally, it populates the array $arr, using a key of the lowercased string version of $matches[3][$n], with a value of $matches[1][$n].

It then, before returning the array itself, populates $arr['maxLength'] with $len from earlier.

How all this works past this point is beyond me -- it would require a lot more RE'ing than I'm willing to put in. It looks like this tool can also **generate** label files, and the syntax it uses it kind of obvious:

Code: Select all

function outputLabels($arr, $text)
{
   global $origin;

   $ret = commentHeader($text);

   foreach ($arr as $n => $v)
   {
      if ($n == 'maxLength')
      {
         continue;
      }

      if (hexdec($n) < $origin)
      {
         $ret .= str_pad($v , 20) . ' = $' . $n . "\n";
      }
   }

   return $ret;

}
Looks to me like label = $address.

I hope this helps. But odds are if you want to troubleshoot/debug this yourself, you're going to need a full PHP install on the system and start running the .php script directly through the interpreter (i.e. not using disasm6.exe) and add some debugging echo/print statements, etc...
charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Thanks for the explanation. Believe it or not, I actually did almost exactly what you did in your response (I promise, swear, and affirm that I did it), using an on-line "run php scripts" website.
After some 4 days or so, I was able to determine what the syntax was supposed to be (label = $xxxx) by copying selected parts of the php source (the same functions you did, for obvious reasons) and get all the way through to the same point where you did:

==>It then, before returning the array itself, populates $arr['maxLength'] with $len from earlier.<==.

At that point I ran into two problems:
1. I could not get the label array (matches[]) to give me more that a single output, even with multiple label assignments in the label file, and
2. I could not get ANY response out of disasm6.

I assumed both of these problems were because of improper formatting of the label file, which I why I tried so many different combinations and got rather frustrated. Imagine how much more frustrated I became when I found the previous post I mentioned, in which a screen shot of a (presumably) correct label file is included, and it MATCHED my file (as best as I can tell)!

At that point, I began to investigate exactly what you suggested...installing PHP on Win10 and debugging it. But the PHP install seems very complicated, and I realized that before I dug into all that, I should probably ask for help here...so I took the chance.

Well, I'm gratified to learn that my 4-day "learn minimum php by total immersion"(!?!?) project was not all in vain, and at least you have provided evidence of my sanity in my attempted analysis of the code!

Thanks very much for your help, your confirmation of my thought processes is certainly a step forward in that it verifies my studies so far.

I shall continue my research, going onward and upward, never ceasing, always moving forward...etc, etc. blah,blah,blah.

If I have any success, I'll certainly report it.

Seriously, thanks for what you did. At least I know I'm on the right track!

Charlie
charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Umm, GOT IT!

I had to re-read your post twice before I caught what I had been overlooking (being so concentrated on the code and all).
Exactly as you had indicated, I was using the wrong command syntax for user-define labels. You said:

=>>That means disasm6 -l filename not disasm6 -lfilename<==

It never occurred to me that the usage was "space" specific!

Thanks for forcing me to re-re-re-review!

Charlie
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by tepples »

koitsu wrote:You choosing to exclude the space is a bad habit. Not all argv parsers are going to be able to handle that properly; maybe you wanted -l -f -i shorthand as -lfi for example.
Then the program's command line syntax is nonstandard. It's the convention in POSIX (apart from grandfathered tar, find, and dd) that an option either always takes an argument or never takes one. For example, if -l and -f never take an argument, -l -f -i means the same as -lfi. Or if -l always takes an argument, -lfi means -l fi.

Another way to look at it: If -l something means one thing and -l -f means something else, then how do you pass the name -f as the value of the -l argument?

My first instinct would be to file an issue on the basis of least astonishment. But is there a public bug tracker? Is there even a maintainer?
charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Yup, that's my background also, which is of course why I did it that way. Things like "-x -y -z" operating the same as "-x-y-z", operating the same as "-xyz" were all normal to me.
Anyway, it works great. Thanks to all who have helped me so far.

But, now I am curious. Obviously, NES is a rather (ahem!) legacy system. So maybe progs like DisAsm6 and Asm6 are not so useful anymore, at least not for the general mainstream. But, with there still being available retro consoles, which can take a homebrew cart, and the plethora of emulators across numerous platforms...is there not any interest in updating and expanding progs like these at all? Is it worth moving to, say, C# or VB, and making a Win GUI app out of them? Or maybe something more up-to-date on the graphics/tile/background image generator side? Or is the "dying breed" just further dying?

(Uh, uh, apparently I've been bitten by the Nintendo mini bug!!)

Thanks
Charlie
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by koitsu »

Both asm6 and disasm6 are open-source. So when you say "updating or expanding progs like these", you are welcome to do so yourself. Licenses for each:

asm6 (from README.txt):

Code: Select all

This is free software.  You may use, modify, and / or redistribute any part
of this software in any fashion.
disasm6: there is none; author says do whatever you want with it as long as he gets credit for the original/base (reference).

asm6 is still heavily used. There are other threads on this board/forum discussing popularity of 65xx assembler suites. Sticking a GUI on front of asm6 would gain you literally nothing. GUIs are not not inherently better-suited for things of this nature -- a debugger is a different situation than an assembler. This is all *horribly* off-topic.

The Wiki maintains a common list of tools; feel free to use whatever works best for you and your needs/situation.
tepples
Posts: 22705
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by tepples »

charliee1151 wrote:Is it worth moving to, say, C# or VB, and making a Win GUI app out of them?
I'd recommend making a GUI app that wraps a command-line disassembler. Not everybody uses Windows; at least calima and I use GNU/Linux. And not everybody prefers using a GUI every time, especially people who want to use disasm6 as a step in a build process. If you make the GUI and the actual disassembler separate processes, you can have the GUI display an equivalent command line that the user can copy and paste into a batch file/shell script, a makefile, etc. Then someone can make a ROM hack that is distributed as a difference file and a batch file/shell script that performs steps 2-4 of the following process:
  1. Obtain a ROM somewhere, such as by dumping your authentic Game Pak using Kazzo.
  2. Disassemble.
  3. Patch the disassembly using the provided diff.
  4. Re-assemble the patched program.
charliee1151
Posts: 22
Joined: Mon Dec 26, 2016 8:58 am

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by charliee1151 »

Agree it's off-topic, and I DON'T want to start a discussion here, just get a quick answer. My interest is simply caused by the situation that I don't know PHP (very much evidenced by my previous posts). Had the progs been in VB or C#, I could debugged them much more easily.

Again, just curious.

Thanks, and yes, let's end this topic here.

Charlie
kuja killer
Posts: 130
Joined: Mon May 25, 2009 2:20 pm

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by kuja killer »

Has this program been abandoned permenately ??
I've been using this with megaman 3 alot recently in the past few days to dissassemble and comment the C000-FFFF (fixed bank), and ran into a glitch involving branches that go 7F bytes forward or 80 bytes backward.

In this screenshot i took, the disasm6 did not do this 1 specific branch in megaman 3 correctly:
http://s31.postimg.org/5pk0v34ij/zcsdffd.png - This BEQ #7F which should go to $F0F1 just like the FCEUX debugger shows, however the disasm6 went in the wrong direction to EFF1

So i have to constantly keep changing that to point to a label name 7F bytes forward. But next time i run disasm6 to add more labels to locations, or RAM addresses, it reverts back to that eff1 again which is wrong. :|
so this was a glitch obviously with disasm6 ..is the author not ever updating this anymore ??
frantik
Posts: 377
Joined: Tue Mar 03, 2009 3:56 pm

Re: DISASM6 v1.5 - Nes oriented disassembler producing asm6

Post by frantik »

FrankWDoom wrote:So I tried this against a CNROM game and it seems to run into trouble right away:

...

that .hex 85 business is obviously not data- should be STA $15
I tried feeding a CDL from fceux in but that doesn't seem to have any affect.

Is there something else I should be doing? I've also never used the CDL thing so maybe I'm doing that wrong?

I've been running like so: disasm6 "elfland (unl).nes" -cdl "elfland (unl).cdl"
Well I doubt you'll see this but you should try running the option -iw or -ignorewrites which ignores writes to $8000 - $FFFF
koitsu wrote: Deeper into the rabbit hole we go, and more abstraction for no justified reason, hooray! The only thing that uses readLabelText() is readLabels(). It's also fantastically super awesomely amazing that the way this works is by passing the ENTIRE FILE CONTENTS as an argument, rather than just handing it a file handle or reference! *cough* So, let's look at that function...
the weird thing is readLabelText was added in 1.5.. in 1.4, readLabels did everything. I'm sure I had a good reason.

I haven't worked on this in a while but I guess people still use it?! There's even a good bug report up there. I can't promise I'll work on this again but let me know your wish lists now..
Post Reply