Jump to content
IGNORED

Stella 3.1 released


stephena

Recommended Posts

Looking further, disassembly doesn't work when the current PC doesn't match the address range the bank was assembled to. If you need a test case, any bankswitched bB program will do this upon entering a new bank. Things get better once the PC changes by a JMP or JSR (or in bB's case, the first RTS) and it does seem to get better after a while but there is definitely some warm-up time, and when re-entering a bank, things seem to go back to square one. You can use the attached game demo above to see this (do a breakif {_bank == 1} to see.)

 

As for disassembling "from the last valid address that was used the last time this bank was entered," this is not good. All bankswitches among banks with different address ranges will result in error and the PC will not be in the correct range until the first jump. For example, an F8 game may be assembled with $D000-$DFFF in bank 0 and $F000-$FFFF in bank 1. Bankswitching will almost always have the wrong address range upon entry - for example, bank 0 encounters a LDA $1FF9 and bank 1 is entered with PC=$Dxxx.

 

Perhaps the best solution here is to remember the address range of the bank just before it was last exited. Also, to mitigate warm-up issues, I'd use the reset vector as a guide first and never the first PC. Sometimes the reset vectors may be wrong but they won't always be wrong like the first PC will in some games.

I'm in the middle of some real-life stuff right now, so I won't be able to get to this until Tuesday or so. But I can comment in more detail on the above. The algorithm for disassembly is as follows:

 

Upon starting to disassemble a bank:

1.  If this bank is the startup bank, set PC to the reset vector address, and remember this start address for that bank
2.  If not the startup bank, and a previous entry point to this bank was used, try to disassemble from that address
3.  If not the startup bank, and a previous entry point to this bank was not used, try to disassemble from the PC, and 'remember' this start address

 

After thinking about it a little and considering your comments, I can see that there's some cases left out of that logic ...

Link to comment
Share on other sites

These comments about disassembling have encouraged me to try my hand at writing a disassembler for the Atari 2600. I wrote a simple 6502 disassembler a *long* time ago on either the Commodore VIC-20 or Atari 8-bit computer, so it's not like I'm a total idjut. :dunce:

 

Yeah, I know that we already have Distella-- but it's a command-line program, and I'm not always happy with the results; from what I've seen, you usually have to do an initial disassembly, check the results, then start building a config file for the game to tell Distella where known sections of code and/or data are, so arriving at a decent disassembly can be a multi-phase job. Also, it doesn't handle bankswitched ROMs.

 

And we also have DIS6502 for the Atari, which is a nice Windows disassembler-- but it's specifically for the Atari 8-bit computers; and even though you can create a set of labels for the 2600 (as I did), it wasn't programmed to automatically disassemble 2600 ROMs-- it doesn't check the RESET vector and start from there. Still, its design is such that you can load a ROM, flag everything as the "byte" (so it won't be disassembled automatically), check the RESET vector yourself, and then start flagging things as "code" or "data" manually. That's not so different from having to build your own config files for Distella, except it's an interactive process. Also, you can click on a label and DIS6502 will show you all the lines that reference it-- well, most of them, anyway, since I noticed last night that it doesn't show branch instructions that target the label (since they use offsets rather than addresses).

 

So I decided it would be nice to have a disassembler like DIS6502, but specifically designed for the Atari 2600. Ideally, it would handle bankswitched ROMs as easily as 2k and 4k ROMs, although you might need to tell it that a particular game uses a particular bankswitching method. I figure it should be an interesting project to pursue, and will give me a chance to learn Visual Basic 2010 Express (I'm definitely *not* a Visual Basic programmer yet). Of course, it might take me a *long* time to write it. I'm going to call it DIS2600, and model it after DIS6502, but not strictly so, because there are some things I can't do in DIS6502 that I wish I could.

 

Michael

  • Like 1
Link to comment
Share on other sites

Looking further, disassembly doesn't work when the current PC doesn't match the address range the bank was assembled to. If you need a test case, any bankswitched bB program will do this upon entering a new bank. Things get better once the PC changes by a JMP or JSR (or in bB's case, the first RTS) and it does seem to get better after a while but there is definitely some warm-up time, and when re-entering a bank, things seem to go back to square one. You can use the attached game demo above to see this (do a breakif {_bank == 1} to see.)

 

As for disassembling "from the last valid address that was used the last time this bank was entered," this is not good. All bankswitches among banks with different address ranges will result in error and the PC will not be in the correct range until the first jump. For example, an F8 game may be assembled with $D000-$DFFF in bank 0 and $F000-$FFFF in bank 1. Bankswitching will almost always have the wrong address range upon entry - for example, bank 0 encounters a LDA $1FF9 and bank 1 is entered with PC=$Dxxx.

 

Perhaps the best solution here is to remember the address range of the bank just before it was last exited. Also, to mitigate warm-up issues, I'd use the reset vector as a guide first and never the first PC. Sometimes the reset vectors may be wrong but they won't always be wrong like the first PC will in some games.

OK, I said I wouldn't look at this until Tuesday, but my OCD kicked in, and I have to talk about it now :)

 

I see that when breaking into bank 1, you'll only see 4 disassembled instructions: PLA, TAX, PLA, RTS. The rest of the ROM will show as raw .byte data only. Is this correct? If so, this is how Distella works. In this case, Distella is disassembling from $ffee, and as it traces the code, it can only see until the RTS. Put another way, from the POV of $ffee, those 4 instructions are the only valid commands in the entire address space. This is how Distella is designed, and I'm not sure how to work around it.

 

I was under the assumption (explained by Thomas J. in another thread) that the PC doesn't have to be aligned starting from $f000, so I can't just start from there and hope that $ffee is part of the results. In fact, that's the way the old disassembler worked, and it often gave incorrect results for just that reason.

 

My (admittedly limited) understanding of bankswitching is that the new bank can essentially be thought of a separate functions, and they can appear anywhere and on any boundary. So if we enter on $ffee, in what other possible way can the remainder of the code be interpreted??

 

Going back to the original example, you'll notice that even after processing the RTS and showing more disassembly, there will still be large parts of the address space that are raw .byte data. Long story short, Distella diassembles from a starting address going as deep as possible. If some part of the address space can't be reached in this fashion, it's considered as dead code. Turning resolve to 'Never' will of course show it, but that introduces other problems.

Link to comment
Share on other sites

Looking further, disassembly doesn't work when the current PC doesn't match the address range the bank was assembled to. If you need a test case, any bankswitched bB program will do this upon entering a new bank. Things get better once the PC changes by a JMP or JSR (or in bB's case, the first RTS) and it does seem to get better after a while but there is definitely some warm-up time, and when re-entering a bank, things seem to go back to square one. You can use the attached game demo above to see this (do a breakif {_bank == 1} to see.)

 

As for disassembling "from the last valid address that was used the last time this bank was entered," this is not good. All bankswitches among banks with different address ranges will result in error and the PC will not be in the correct range until the first jump. For example, an F8 game may be assembled with $D000-$DFFF in bank 0 and $F000-$FFFF in bank 1. Bankswitching will almost always have the wrong address range upon entry - for example, bank 0 encounters a LDA $1FF9 and bank 1 is entered with PC=$Dxxx.

 

Perhaps the best solution here is to remember the address range of the bank just before it was last exited. Also, to mitigate warm-up issues, I'd use the reset vector as a guide first and never the first PC. Sometimes the reset vectors may be wrong but they won't always be wrong like the first PC will in some games.

OK, I said I wouldn't look at this until Tuesday, but my OCD kicked in, and I have to talk about it now :)

 

I see that when breaking into bank 1, you'll only see 4 disassembled instructions: PLA, TAX, PLA, RTS. The rest of the ROM will show as raw .byte data only. Is this correct? If so, this is how Distella works. In this case, Distella is disassembling from $ffee, and as it traces the code, it can only see until the RTS. Put another way, from the POV of $ffee, those 4 instructions are the only valid commands in the entire address space. This is how Distella is designed, and I'm not sure how to work around it.

 

I was under the assumption (explained by Thomas J. in another thread) that the PC doesn't have to be aligned starting from $f000, so I can't just start from there and hope that $ffee is part of the results. In fact, that's the way the old disassembler worked, and it often gave incorrect results for just that reason.

 

My (admittedly limited) understanding of bankswitching is that the new bank can essentially be thought of a separate functions, and they can appear anywhere and on any boundary. So if we enter on $ffee, in what other possible way can the remainder of the code be interpreted??

 

Going back to the original example, you'll notice that even after processing the RTS and showing more disassembly, there will still be large parts of the address space that are raw .byte data. Long story short, Distella diassembles from a starting address going as deep as possible. If some part of the address space can't be reached in this fashion, it's considered as dead code. Turning resolve to 'Never' will of course show it, but that introduces other problems.

That is essentially what I'm getting. It's fine for the first time you enter the bank as I suppose we are never sure if it's code or data, but for future entries into the bank, there should be something better. Perhaps certain addresses could be cached and marked as code so the disassembly doesn't go back to square one upon every entry into a new bank. I don't think many addresses would need to be cached, just those that enhance the disassembly.

Link to comment
Share on other sites

Perhaps certain addresses could be cached and marked as code so the disassembly doesn't go back to square one upon every entry into a new bank. I don't think many addresses would need to be cached, just those that enhance the disassembly.

You only have to add jumps to addresses which are outside the currently known code area. And later on, you can remove addresses which are in the middle of the already known code area. So when a bank is fully executed once, there should be maybe 10 or less (depending on size of jump tables used in the code) addresses from where to start disassembling.

Link to comment
Share on other sites

Going back to the original example, you'll notice that even after processing the RTS and showing more disassembly, there will still be large parts of the address space that are raw .byte data. Long story short, Distella diassembles from a starting address going as deep as possible. If some part of the address space can't be reached in this fashion, it's considered as dead code. Turning resolve to 'Never' will of course show it, but that introduces other problems.

That is essentially what I'm getting. It's fine for the first time you enter the bank as I suppose we are never sure if it's code or data, but for future entries into the bank, there should be something better. Perhaps certain addresses could be cached and marked as code so the disassembly doesn't go back to square one upon every entry into a new bank. I don't think many addresses would need to be cached, just those that enhance the disassembly.

Caching the disassembly results (ie, a progressive disassembly that gets better after multiple passes because of new knowledge) will probably require a redesign of the Distella code. But I agree that it would give much better results. This is something I can consider for a future release, but I probably can't squeeze it in for 3.2 (which will be released in August).

 

But what about the pathological case where the same section of ROM can be treated as both code and data? This is particularly relevant for SARA or ZP RAM, which can be modified on-the-fly (aka, self-modifying code). Say I cache address X as code. Later, address X could be interpreted as data. Or, say that address X consists of a 2-byte instruction, and later the PC starts executing from X+1. I'm not sure how to work around these issues.

 

In any event, for now and until this is fixed, you can just turn off resolving data vs code sections (ie, set resolve data to 'never'), and you'll always see all the bytes interpreted as code.

Link to comment
Share on other sites

In any event, for now and until this is fixed, you can just turn off resolving data vs code sections (ie, set resolve data to 'never'), and you'll always see all the bytes interpreted as code.

Maybe Stella could use the configuration files DiStella uses? Not automatic, but better than nothing.

Link to comment
Share on other sites

But what about the pathological case where the same section of ROM can be treated as both code and data?

 

 

Illegal NOP's, BIT, and CMP instructions are also sometimes used to skip a few bytes. I would suggest if the disassemlblier catches a branch into a BIT instruction then do something like:

 

 

.byte $2C ; BIT opcode

LABEL_HERE:

LDA #$45

 

With the "; BIT opcode" behind the the byte, you know explicitly that the BIT instruction is being used to skip 2 bytes in this case, and that it is not meant as a data byte.

Link to comment
Share on other sites

In any event, for now and until this is fixed, you can just turn off resolving data vs code sections (ie, set resolve data to 'never'), and you'll always see all the bytes interpreted as code.

Maybe Stella could use the configuration files DiStella uses? Not automatic, but better than nothing.

This could be a possibility, but I have to play with Distella and the config files a little more to see how it all works. There's already a tracker request added for this too. In any event, it will have to wait until after 3.2.

Link to comment
Share on other sites

just curious if it was possible to make the phosphor crt tv effects compatible with opengl 1.4 in the next or future version?

Those effects are probably going to be removed, and replaced with NTSC CRT emulation (aka, Blargg algorithm) sometime in the future. The current code is unmaintained, and the Blargg filtering should look just as good, and potentially be faster and not restricted to OpenGL. These changes won't be done until after the 3.2 release.

  • Like 1
Link to comment
Share on other sites

I tried to use the Genesis emulation but it didn't work. Do I need to use the P1 or P0?

There are three requirements for Genesis controller emulation:

 

1) The ROM must be programmed/hacked to work with the Genesis controller.

 

2) The controller must be set to 'Genesis' in Options -> Game Properties -> Controller. Use P0 for the left pad, or P1 for the right pad.

 

3) You have to know which Genesis 'buttons' are mapped to which Stella actions. Genesis button B is the same as the normal fire button (by default, either LeftControl or Space), and Genesis button C is the same as the BoosterGrip booster button (by default, the 5 key). These events can be remapped, but of course then you're changing the mappings for a normal joystick/BoosterGrip controller too.

Link to comment
Share on other sites

  • 2 weeks later...

I've found a few bugs in Stella, and I don't know when they appeared or if they've been reported already or not. I will list them in no particular order:

  • runto in the debugger no longer works (Stella hangs or crashes no matter the argument)
  • You can no longer switch banks from the debugger using "bank" from the console or changing the bank number from the bank number text box
  • 3x video mode doesn't work, nor does software rendering (both crash Stella, but could be my hardware)
  • Disassembly sometimes shows no instructions at all in "Automatic" mode even when many legitimate instructions exist
  • Debugger "exec" command sometimes crashes Stella (can't repeat right now)
  • VBLANK bit 6 to latch joystick buttons doesn't work

That's all for now...

The 'runto' command has been fixed. It was case-sensitive, so it never found any matches most of the time. However, even if a match isn't found, the search will stop after looking through the entire bank (give or take a little). It may seem that the program has locked up, but give it a few moments. Of course, if it doesn't come back after an extended time, then it is definitely a bug. Note that this is because the home-grown UI doesn't support multi-threading, so I can't (easily) give feedback of the search while it's proceeding. I'll look into how hard it would really be to add feedback.

 

Changing banks and incomplete disassembly issues have been added to the Stella tracker, and will be addressed for the next release after 3.2. Please subscribe to those threads for more info.

 

I can't duplicate your video issues, so this will have to be addressed later. The same for the 'exec' command, without some test cases.

 

VBLANK bit 6 latch bug is now fixed. There was actually no consideration at all for bit 6 in the TIA code.

 

EDIT: actually, scratch that last comment about the runto command. It's very easy to add a progress bar, just like the one for auditing ROMs. This will be in the next release.

Link to comment
Share on other sites

I've found a few bugs in Stella, and I don't know when they appeared or if they've been reported already or not. I will list them in no particular order:

  • You can no longer switch banks from the debugger using "bank" from the console or changing the bank number from the bank number text box
  • Disassembly sometimes shows no instructions at all in "Automatic" mode even when many legitimate instructions exist

A per the Stella tracker thread on these issues, fixes have been completed, and will be included in the next release. It ended up being easier to fix this than I thought, although debugger 'rewind' is now completely broken as a result ...

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...