DirtyHairy Posted July 28, 2019 Share Posted July 28, 2019 (edited) There has already been a lot of discussion on the precise mechanics of FE banking before. In particular, as explained by @TomSon here and according to the patent, the reset sequence of the 6502 will trigger a bank switch that effectively will cause FE to start in a defined bank. Now, since last summer, I have a new CPU core in 6502.ts that, among other things, models the reset cycle of the CPU precisely. Today, I have noticed that this actually *breaks* FE banking What happens is that the reset sequence causes an access to 0x01fe immediately before loading the reset vector low byte from 0xfffc. However, the low byte is zero (including the high bits that are used for selecting the bank), and this causes the emulated cartridge to switch to bank 1, which contains garbage at 0xf000. After scratching my head for some time, my assumption is that (as the banks are usually selected with the high bit sequences 110 and 111) 000 is in fact treated specially to select the startup bank which is bank0. I have implemented this in 6502.ts, and it works for all FE carts that I am aware of, but I have no way to verify this. Has anybody here ever opened up a FE cartridge and checked what actually is going on inside? Edited July 28, 2019 by DirtyHairy Quote Link to comment Share on other sites More sharing options...
alex_79 Posted July 28, 2019 Share Posted July 28, 2019 I have a PAL "Space Shuttle" cartridge. I'll crack it open later today, but probably the bankswitching logic is integrated within the rom chip and there won't be anything to see. What about running some test code from RIOT RAM to trigger bankswitching and see what bank is selected when pushig "000" as high bits in the stack? Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted July 28, 2019 Author Share Posted July 28, 2019 2 hours ago, alex_79 said: What about running some test code from RIOT RAM to trigger bankswitching and see what bank is selected when pushig "000" as high bits in the stack? That's a good idea. I think I can cook up a test ROM, but I don't have a cartridge to test. If I put together a test, would you mind giving it a try? Quote Link to comment Share on other sites More sharing options...
alex_79 Posted July 28, 2019 Share Posted July 28, 2019 38 minutes ago, DirtyHairy said: If I put together a test, would you mind giving it a try? Sure. I attach here a dump of my cart, so you know what values you should read in each bank. (It 100% matches the known PAL rom, anyway) dump.bin Quote Link to comment Share on other sites More sharing options...
alex_79 Posted July 28, 2019 Share Posted July 28, 2019 In the meantime, I tried making a test rom myself: The rom performs a series of jsr and rts and reads the value at $FFFD inside the subroutine (shown on the left) and after returning from it (on the right). The value read at that address is $F0 in bank 0 and $D0 in bank 1. The sequence of the address 3 high bits of the subroutine is increased on each row ($0xxx, $2xxx, $4xxx and so on up to $Exxx). Then the return address is increased in the same way and the sequence repeats. So there are 8 groups (one per each return address) with 8 values each (one for each subroutine address). This is the result with my "Space Shuttle" cart: Basically, only bit 13 of the address determines the bank (A13=0 -> bank 1, A13=1 -> bank 0) the two highest bits don't matter, and a sequence of three '0' doesn't behave in a different way (it selects bank 1). testFE.zip 1 Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted July 28, 2019 Author Share Posted July 28, 2019 Nice, you beat me to it, I was still debugging my own test ROM I took another look at the Space Shuttle ROM, and this one actually contains a valid reset vector in bank 1, too, and has a JSR at the beginning of bank 1 that will switch over to bank 0. So, Space Shuttle starts up correctly in bank 1. I doublechecked, and the only example that really doesn't work (aka fails in bank 1) with the correct reset sequence is Decathlon, which I stumbled over in the first place. Now we'd need someone with a decathlon cartridge... Quote Link to comment Share on other sites More sharing options...
alex_79 Posted July 29, 2019 Share Posted July 29, 2019 (edited) After doing a bit of research, I'm thinking that your implementation of the FE bankswitching is correct the way it is now, and the problem with "Decathlon" comes from the assumption that the Stack Pointer is 00 after the RESET line goes high. The "MOS 6500 family programming manual", on page 126 says: While the reset line is in the low state, it can be assumed that internal registers may be initialized to any random condition; therefore, no conditions about the internal state of the microprocessor are assumed other than that the microprocessor will, one cycle after the reset line goes high, implement the following sequence: Example 9.1: Illustration of Start Cycle Cycles Address Bus Data Bus External Operation Internal Operation 1 ? ? Don't Care Hold During Reset 2 ? + 1 ? Don't Care First Start State 3 0100 + SP ? Don't Care Second Start State 4 0100 + SP-1 ? Don't Care Third Start State 5 0100 + SP-2 ? Don't Care Fourth Start State 6 FFFC Start PCL Fetch First Vector 7 FFFD Start PCH Fetch Second Vector Hold PCL 8 PCH PCL First OP CODE Load First OP CODE Note that on cycles 3,4,5 the manual doesn't define an absolute address on the bus, but rather an offset from $100 which depends on the SP value. At the end of this sequence, the SP is $FD only if it was $00 after a RESET, but according to the previous paragraph, the internal registers (including SP) may be initialized with any random value. Still, I clearly remember that a while ago there were discussions on the forum on this very same subject. Links to analysis of the cpu power-on sequence and also the results of test roms run on the 2600 brought to the conclusion that after the startup sequence the value of SP in a 2600 is determined and this value is $FD. (This has been implemented in Stella too) So I went back reviewing those dicussions. Here is the relevant thread: https://atariage.com/forums/topic/261488-reset-sp/ The document TomSon was referring to is here: https://www.pagetable.com/?p=410 If you scroll down that page, in the section "RESET" it states: Cycle 0: When a 6502 is turned on, the stack pointer is initialized with zero. The source of this piece of info seems to be the Visual6502 simulator. Further down in the AA thread, Tomson posted a testrom displaying a colored screen if SP value was $FD at startup, and I posted a testrom too displaying the SP value and confirmed $FD as the result in a 2600 (Note: that rom has a bug in that it doesn't initialize the D flag, which sometimes results in corrupted display). There's also a link to another testrom by Omegamatrix showing a more detailed view of the startup state of the VCS, including the entire ram and all the CPU registers. Case closed, I guess. No, actually. I repeated those tests with the console I have currently hooked up (a 2600 Jr). I tried all 3 test roms (flashing them in single game mode on the harmony) and the value of SP is completely random and changing on each power cycle on this machine! So I pulled out of storage a couple more consoles to test (a 4 switch and a 6 switch). The result here is often $FD, but not always. The 6 switch, returned $FD for several powercycles after a cold start. Anyway, as it got warmer, it started to return different values sometimes ($7D and $FC, mostly). The 4 switch behaves the opposite: the values mostly stabilize as it gets warmer to $FD. (and the D flag is set more often when is warm too, revealing the bug in my testrom...) So, at the time, I only did a few tests on one console, which happened to match what was being stated. Since the source of that info seemed to be an authorative one, I had no reason to doubt it, and didn't test further. Edited July 29, 2019 by alex_79 2 Quote Link to comment Share on other sites More sharing options...
+stephena Posted July 29, 2019 Share Posted July 29, 2019 Hmm, I thought we had this one figured out for good. Looks like there's still more work to do. For what it's worth, it's working fine in Stella, but that may be because we coded it to work to the ROMs, and not to the actual underlying behaviour. In Stella, the bankswitch doesn't happen until the next cycle. So the address is strobed on one cycle, and the actual switch happens on the next. Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted July 29, 2019 Author Share Posted July 29, 2019 (edited) 10 hours ago, alex_79 said: No, actually. I repeated those tests with the console I have currently hooked up (a 2600 Jr). I tried all 3 test roms (flashing them in single game mode on the harmony) and the value of SP is completely random and changing on each power cycle on this machine! So I pulled out of storage a couple more consoles to test (a 4 switch and a 6 switch). The result here is often $FD, but not always. The 6 switch, returned $FD for several powercycles after a cold start. Anyway, as it got warmer, it started to return different values sometimes ($7D and $FC, mostly). The 4 switch behaves the opposite: the values mostly stabilize as it gets warmer to $FD. (and the D flag is set more often when is warm too, revealing the bug in my testrom...) So, at the time, I only did a few tests on one console, which happened to match what was being stated. Since the source of that info seemed to be an authorative one, I had no reason to doubt it, and didn't test further. Interesting, thanks alot! I just played a bit more with decathlon, and I think I have found what is going on: there still are still a few undocumented opcodes in 6502.ts that I haven't implemented (which, I think, are unstable on hardware), and that's what is causing the issue. If I stub out those with NOPs, then Decathlon actually runs. The same happens if I start Decathlon with Stella in bank 1. Looking at the trace in 6502.ts it seems that, somehow, it manages to run through garbage until it finally, by magic, hits BRK with S and P in the right state to switch back to bank 0 when pushing PCL. BRK then jumps to the interrupt vector in bank 0 (which is 0xf000) and the program finally enters the startup code. I am pretty sure David Crane didn't do that one on purpose Sorry for the confusion, time to implement those opcodes I guess... Edited July 29, 2019 by DirtyHairy 1 Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted July 29, 2019 Author Share Posted July 29, 2019 9 hours ago, stephena said: In Stella, the bankswitch doesn't happen until the next cycle. So the address is strobed on one cycle, and the actual switch happens on the next. In Stella, the whole issue cannot be reproduced as we don't emulate the reset sequence --- on reset, the CPU starts with the reset vector already loaded in P, so the problematic bank switch cannot happen in the first place. Quote Link to comment Share on other sites More sharing options...
+stephena Posted July 29, 2019 Share Posted July 29, 2019 10 minutes ago, DirtyHairy said: In Stella, the whole issue cannot be reproduced as we don't emulate the reset sequence --- on reset, the CPU starts with the reset vector already loaded in P, so the problematic bank switch cannot happen in the first place. Do you think it's worthwhile to implement this in Stella too? Quote Link to comment Share on other sites More sharing options...
DirtyHairy Posted July 29, 2019 Author Share Posted July 29, 2019 (edited) 16 minutes ago, stephena said: Do you think it's worthwhile to implement this in Stella too? Apart from a possible interaction with emulated bankswitching hardware (like here), the reset sequence has no detectable effect, so I don't think there is any real reason to implement it. However, I don't think it is hard to do, either If you like, let's open a ticket --- I can do it once I have fixed decathlon in 6502.ts for good (I'd like to have a final confirmation that my reasoning is really correct here). Edited July 29, 2019 by DirtyHairy 1 Quote Link to comment Share on other sites More sharing options...
alex_79 Posted July 30, 2019 Share Posted July 30, 2019 7 hours ago, DirtyHairy said: Looking at the trace in 6502.ts it seems that, somehow, it manages to run through garbage until it finally, by magic, hits BRK with S and P in the right state to switch back to bank 0 when pushing PCL. BRK then jumps to the interrupt vector in bank 0 (which is 0xf000) and the program finally enters the startup code. I am pretty sure David Crane didn't do that one on purpose Interesting, thanks for the explanation! BTW, I opened my "space shuttle" cart and indeed, there's nothing useful there to check (that is, unless someone decap that chip-on-board and reverse engineer it using an electron microscope...) Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.