+SpiceWare Posted January 19, 2020 Share Posted January 19, 2020 Added routines to detect information about the console. Source Code Download and unzip this in your shared directory. Collect3_20200120.zip ROM for reference collect3_20200120.bin 2600 / 7800 Detection Back in 2005 @Nukey Shay asked if it was possible to detect if the program is running on a 2600 or 7800. @batari figured out that the 128 bytes of Zero Page RAM is in a random state on the 2600, but on the 7800 the RAM ends up in a known state due to what the 7800's startup sequence does before it switches into 2600 mode. @batari posted a test program in reply #18 that checks if the contents of ZP RAM locations $D0 and $D1 came back as $2C and $A9 - if they do the console's a 7800, if they don't the console's a 2600. What this is useful for is the pause button on a 7800 is wired to the same bit in SWCHB that the 2600's TV Type toggle is wired to, but the pause button is a momentary switch which behaves differently than a toggle. By knowing which console the program is on it can run different code to implement a pause feature monitoring the 2600's TV TYPE switch as well as the 7800's Pause button. The menu on the Harmony checks $D0 and $D1 to detect the console type. When a game is loaded the 2600 needs to be idled, so an idle routine is copied into ZP RAM that overwrites the values in $D0 and $D1. The idle routine is aware that some programs have console detection logic, so after the game is loaded the idle routine will put the values needed in $D0 and $D1 RAM for console detection. The CDFJ driver has 2 different startup routines: game launched via the Harmony Menu game flashed onto Harmony/Melody The CDFJ driver takes some time to initialize, so the 2600 must be idled for a brief period of time. If the game was launched via the Harmony Menu then CDFJ just utilizes the Harmony Menu's idle routine that's already in RAM. If flashed onto the Harmony/Melody board the CDFJ driver puts its own idle routine into ZP RAM. Like the Harmony Menu the CDFJ idle routine detects console type, but instead of restoring the values in $D0 and $D1 it zeros out $D0 and $D1 and puts the detected console in $80. So the console detection for CDFJ games does this: if ZP RAM $D0 contains $2C and ZP RAM $D1 contains $A9 console = 1 ; 7800 else if ZP RAM $D0 contains $00 and ZP RAM $D1 contains $00 console = value found in ZP RAM $80 else console = 0 ; 2600 The InitSystem routine in the 6507 code now starts out with a console detection routine, the results of which end up in the Y register. It then does the usual init, but passes the value in Y onto the C routine Initialize() which saves it in a new variable is_7800. At the moment is_7800 is only used on the initial splash screen to show which console was detected. Eventually we'll use it for a pause feature. 2600 detected 7800 detected NTSC / PAL / SECAM Detection Back in 2015 @ZackAttack put forth the idea of using a timer in the ARM processor to detect if a console was NTSC or PAL, which would allow a game to auto-adjust for console differences such as the color palette. A couple years later I followed up on that and created a NTSC vs PAL detection program. Tests showed that while there was some variation in the results, the difference between NTSC and PAL was enough for it to work. While I was working on routines to emulate the ARM's timer in Stella, @alex_79 made me aware that clock for SECAM was also different. Knowing that, I was able to expand the detection to include SECAM. This detection occurs in function SplashVerticalBlank(). It works by starting the timer on frame 1, then stopping the timer on frame 2 and seeing how long it ran. Expected times for each system are: 11d329 for NTSC 11e8ff for SECAM 11fd2b for PAL To allow for minor hardware variations the detection uses the midpoint between SECAM & NTSC and the midpoint between PAL & SECAM: if (T1TC < (0x11e8ff + 0x11d329)/2) tv_type = NTSC; else if (T1TC > (0x11fd2b + 0x11e8ff)/2) tv_type = PAL; else tv_type = SECAM; Once we know the TV Type the console is for, we can do on-the-fly conversions of NTSC color values to PAL or SECAM. Check out function ColorConvert() in main.c. By default Stella will autodetect the game as NTSC because of the 262 scanlines of output: NTSC console detected, $44 used for RED NTSC Player coloration You can tell the autodetect occurred because of the * after NTSC. We can override the game properties and set the Display Format to PAL60 or SECAM60. After doing that just reload the ROM for the change to take effect. Change Game properties Display Format to PAL60 Collect 3 now uses $64 for RED for PAL PAL Player coloration Change Game properties Display Format to SECAM60 Collect 3 now uses $04 for RED for SECAM SECAM Player coloration 3 Link to comment Share on other sites More sharing options...
Lillapojkenpåön Posted January 20, 2020 Share Posted January 20, 2020 Wasn't there talk about implementing detection in Stella as well, by looking for strings in the filename like NTSC, SECAM, PAL60 etc. I hope that's still on some to do list somewhere because that was a great idea. I allways wondered how you did this, very cool! Why aren't we converting the players to? 1 Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted January 20, 2020 Share Posted January 20, 2020 2 hours ago, Lillapojkenpåön said: Wasn't there talk about implementing detection in Stella as well, by looking for strings in the filename like NTSC, SECAM, PAL60 etc. I hope that's still on some to do list somewhere because that was a great idea. I just created a Stella issue for this. 2 hours ago, Lillapojkenpåön said: Why aren't we converting the players to? ??? 1 Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 20, 2020 Author Share Posted January 20, 2020 12 hours ago, Lillapojkenpåön said: Why aren't we converting the players to? I had the feeling I forgot something! I'll do a quick revision and upload new source and ROM. Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 20, 2020 Author Share Posted January 20, 2020 7 hours ago, Thomas Jentzsch said: ??? I forgot to use ColorConvert for the game screen, so instead of the blue and green accent colors seen for the players in NTSC: the players looked like this for PAL: and this for SECAM: I've revised the routines, replaced the source and ROM, and added some screenshots of the players on the game screen. 1 Link to comment Share on other sites More sharing options...
Lillapojkenpåön Posted January 22, 2020 Share Posted January 22, 2020 Now that I'm starting to get how DPC+ and CDFJ works I thought of a thing, if you have both player 0 and player 1 virtual sprites, and two player 1's get to close, couldn't you put one in player 0's buffer (if that position is free) and position in that stream? A fluid system where the buffers and GRP0 and GRP1 are used to draw as much as possible before flickering? That is probably what everybody is doing allready now that I think of it ? Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 22, 2020 Author Share Posted January 22, 2020 Correct, the virtual sprites are not tied to a specific player. Blog entry It's full of stars! goes into some detail on how its done. If you play Draconian in Stella with Fixed Debug Colors mode turned on you can see it in action. In this sequence of frames I drew a white box in an area that contains a mine, the player's ship, and an asteroid. Over 3 frames those objects are drawn like this: player0 - asteroid player1 - player's ship player0 - mine player1 - asteroid player0 - player's ship player1 - mine 1 Link to comment Share on other sites More sharing options...
Dionoid Posted January 24, 2020 Share Posted January 24, 2020 (edited) Thanks Darrell, this NTSC/PAL/SECAM detection is really useful! In your games that implement this detection technique (e.g. Draconian) I see that you still offer the option to change the TV type on the menu screen (with the detected TV type pre-selected). Is this because the detection isn't 100%, or just to give people the option to change it if they want to? Edited January 24, 2020 by Dionoid 1 Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 24, 2020 Author Share Posted January 24, 2020 1 hour ago, Dionoid said: Is this because the detection isn't 100%, or just to give people the option to change it if they want to? The option was because Draconian was the first time we used it in a released game, and I didn't know if the detection was 100% or not. Would probably be worth doing a poll at some point to see how well it's worked for people. Instead of a menu option, an override could be implemented by checking the joystick state when the 2600's powered up: FIRE for NTSC UP for PAL60 DOWN for SECAM60 To do that I'd change SplashVerticalBlank() to this: void SplashVerticalBlank() { ... else if (frame == 2) { T1TCR = 0; // turn off timer after 1 frame // first check if the user overrode the detection // if they did not then use the value in T1TC to see // how long it took the 2600 to draw 262 scanlines if (JOY0_FIRE) tv_type = NTSC; else if (JOY0_UP) tv_type = PAL; else if (JOY0_DOWN) tv_type = SECAM; else if (T1TC < (0x11e8ff + 0x11d329)/2) tv_type = NTSC; else if (T1TC > (0x11fd2b + 0x11e8ff)/2) tv_type = PAL; else tv_type = SECAM; } ... } Link to comment Share on other sites More sharing options...
Lillapojkenpåön Posted January 25, 2020 Share Posted January 25, 2020 How does that work? are those times specific to that exact code, I mean is it adjusted for any c code or 6507 cycles? Or what exactly do I need to be aware of to not change to make sure It keeps working? Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 25, 2020 Author Share Posted January 25, 2020 the 2600 must output 262 scanlines for those times to be valid. If you look at the 6507 code before the ARM runs: VerticalSync: ldy #2 ldx #VB_TIM64T sty WSYNC sty VSYNC stx TIM64T sty WSYNC sty WSYNC ldy #0 ; 2 2 - zero out some TIA registers while sty GRP0 ; 3 5 we have some free time sty GRP1 ; 3 8 sty WSYNC sty VSYNC ; figure out which ARM Vertical Blank routine to run lda Mode ; $00 = splash, $01 = menu, $80 = game bmi vbgame beq vbsplash ldy #_FN_MENU_VB ; going to run function MenuVerticalBlank() .byte $0c ; NOP ABSOLUTE, skips over ldy #_FN_SPLASH_VB vbsplash: ldy #_FN_SPLASH_VB ; going to run function SplashVerticalBlank() .byte $0c ; NOP ABSOLUTE, skips over ldy #_FN_GAME_VB vbgame: ldy #_FN_GAME_VB ; going to run function GameVerticalBlank() jsr CallArmCode you'll see that both frame 1 and frame 2 will follow the exact same path, thus take the same number of 6507 cycles, resulting in exactly 262 scanlines worth of time transpiring between ARM calls. You can add more 6507 code in there as long as the path taken for frame 1 and frame 2 is identical. Likewise in the C code both frames 1 and 2 will take the same path until they get to the IF/ELSE IF block of code in SplashVerticalBlank(). void SplashVerticalBlank() { int i; int j; int color; int console; color = 0; // default to black // used to show if the console is a 2600 or 7800 console = ((is_7800 ? _SPLASH_78 : _SPLASH_26 ) & 0xfff) + 0x6000; if (frame == 1) // frame is incremented in SplashOverScan() { T1TC = 0; // make sure timer starts at 0 T1TCR = 1; // turn on timer } else if (frame == 2) { T1TCR = 0; // turn off timer after 1 frame // the time it takes to output 262 scanlines is different for // NTSC, PAL, and SECAM consoles, so we can use that to detect // which one and adjust the color values. if (T1TC < (0x11e8ff + 0x11d329)/2) tv_type = NTSC; else if (T1TC > (0x11fd2b + 0x11e8ff)/2) tv_type = PAL; else tv_type = SECAM; } The value in T1TC stops changing as soon as T1TCR is set to 0, so the extra lines of code added for joystick override will have no impact on the values being compared against. 1 Link to comment Share on other sites More sharing options...
+SpiceWare Posted January 31, 2020 Author Share Posted January 31, 2020 Making headway on Part 7. The menu is fully functional, what's left is: add the routines to colorize X'd options red clean up the code add comments It'll be sometime next week though as this weekend I'm taking my nephew to Fully Charged LIVE in Austin. 3 Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted February 10, 2022 Share Posted February 10, 2022 On 1/20/2020 at 12:43 AM, SpiceWare said: Expected times for each system are: 11d329 for NTSC 11e8ff for SECAM 11fd2b for PAL These are the only the 6507 cycles, and do not include the extra cycles which the Thumb code takes after starting (~2250), between the two updates (~300) and before stopping the counter (~100), right? Since the emulators may or may not count the Thumb cycles, it might be a good idea to: reduce the Thumbs cycles (especially after starting the counter) adjusting the test values I am not 100% sure, but it seems that the auto detect current only works on real hardware because the gaps between NTSC, SECAM and PAL are large enough (~5400 cycles). Link to comment Share on other sites More sharing options...
+SpiceWare Posted February 10, 2022 Author Share Posted February 10, 2022 8 hours ago, Thomas Jentzsch said: it seems that the auto detect current only works on real hardware because the gaps between NTSC, SECAM and PAL are large enough (~5400 cycles) We did tests on real hardware to validate the ARM timer values. theoretical 11d329 for NTSC, saw 11d311 thru 11d32e theoretical 11e8ff for SECAM, saw 11e8f7 thru 11e8fd theoretical 11fd2b for PAL, saw 11fd00 thru 11fd35 Also conducted a poll in 2020 to see if anybody had incorrect detection. Link to comment Share on other sites More sharing options...
Thomas Jentzsch Posted February 10, 2022 Share Posted February 10, 2022 I remember that and your values are correct. But I think the emulation has some flaws. We are adding fixed numbers of 6507 cycles to the counter. These cycles assume that the Thumb code executes in no time. I think we have to differentiate here when we emulate Thumb cycles. 1 Link to comment Share on other sites More sharing options...
Recommended Posts