Shop OBEX P1 Docs P2 Docs Learn Events
Basic Q's about the Spin2 Interpreter Size, Content and Loading - Page 3 — Parallax Forums

Basic Q's about the Spin2 Interpreter Size, Content and Loading

135

Comments

  • evanhevanh Posts: 15,126

    @JRetSapDoog said:

    @evanh said:
    FLexBASIC has same: clkset(mode, freq) There is no hubset() function in FlexBASIC so can't mess that one up without using assembly.

    FlexC has: _clkset(mode, freq)

    Today, I read about Spin2's clkset() method for safely setting the clock (glitch free), but I've used pasm to do the final handover (and I'm not sure if I can use in-line assembly in Spin2 to do that because I don't know if the pasm loads up in cog registers or still gets pulled in instruction-by-instruction from the hub (which could get clobbered)). Need to look into that, but, for now, I just launched a pasm cog to finish the handover.

    Here's the detailed steps for using HUBSET to adjust the PLL to a new frequency. clk_mode would be a copy of CLKMODE from hubRAM.

            andn    clk_mode, #%11          'clear the two select bits to force RCFAST selection
            hubset  clk_mode            '**IMPORTANT**  Switches to RCFAST using known prior mode
    
            mov clk_mode, new_mode      'replace old with new ...
            andn    clk_mode, #%11          'clear the two select bits to force RCFAST selection
            hubset  clk_mode            'setup PLL mode for new frequency (still operating at RCFAST)
    
            or  clk_mode, #XSEL         'add PLL as the clock source select
            waitx   ##25_000_000/100        '~10ms (at RCFAST) for PLL to stabilise
            hubset  clk_mode            'engage!  Switch back to newly set PLL
            ret         wcz
    

    For a handover, use only the first two instructions. The important detail is having a copy of the prior clock mode that was set.

  • @evanh said:
    My own pure pasm wrapper routines has its own way that doesn't touch hubRAM. I developed it long ago for stepping through many sysclock frequencies. Some of my test code blitzes hubRAM, it's nice knowing everything is contained in the one cog when doing that.

    But how do you get such code into the cog? Through the regular boot process after being loaded into the hub? That is, does the ROM load your code from hub into a cog and then start the cog? Or is there some way of loading code into cog 0 without going through the hub? Your talking to a near novice here. Can't exactly wrap my head around that.

  • evanhevanh Posts: 15,126

    @JRetSapDoog said:
    Thanks, evanh. So, in my little pasm routine to finish the handover (particularly coping the upper hub to the lower hub and doing coginit), you don't think that I need to try to set the clock mode to RCFAST (and you think that doing so could cause glitches)? That is, the new program will just temporarily inherit the clock from the old program, whatever speed it is (likely 10x or so greater than RCFAST) and then it will adjust the clock to whatever speed it wants (perhaps by first going to RCFAST itself). Or am I wrong? Sorry, to keep circling around this.

    Bad idea. By default a newly launched program will not attempt to read CLKMODE or CLKFREQ. It will assume RCFAST and write those with its first clock frequency setting.

  • @evanh said:
    Bad idea. By default a newly launched program will not attempt to read CLKMODE or CLKFREQ. It will assume RCFAST and write those with its first clock frequency setting.

    Ah, okay. Thanks.

  • evanhevanh Posts: 15,126

    In other words. RCFAST handover methodology keeps with the power up default. Every program is the first program.

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 01:25

    @evanh said:

    Here's the detailed steps for using HUBSET to adjust the PLL to a new frequency. clk_mode would be a copy of CLKMODE from hubRAM.

          andn    clk_mode, #%11          'clear the two select bits to force RCFAST selection
          hubset  clk_mode            '**IMPORTANT**  Switches to RCFAST using known prior mode
    
          mov clk_mode, new_mode      'replace old with new ...
          andn    clk_mode, #%11          'clear the two select bits to force RCFAST selection
          hubset  clk_mode            'setup PLL mode for new frequency (still operating at RCFAST)
    
          or  clk_mode, #XSEL         'add PLL as the clock source select
          waitx   ##25_000_000/100        '~10ms (at RCFAST) for PLL to stabilise
          hubset  clk_mode            'engage!  Switch back to newly set PLL
          ret         wcz
    

    For a handover, use only the first two instructions. The important detail is having a copy of the prior clock mode that was set.

    So in my case (file booting), use only:

      andn    clk_mode, #%11          'clear the two select bits to force RCFAST selection
      hubset  clk_mode            '**IMPORTANT**  Switches to RCFAST using known prior mode
    

    wherein I get clk_mode from hub $44 $40 (after I copy the upper hub to the lower hub). The part about masking off the last two bits sounds like what msrobots was talking about earlier in this thread (haven't looked back yet), and I think I saw something about that in the manual, too.

    Update: Whoops! I should have said "hub $40" for the clkmode.

    But doesn't that only work for Spin2??? Update: Yes, but my menu program will be in spin2. I need to get the clkmode for MY program, not the new one. Gee, need to change the above.

    Well, getting the clk_mode for my own (old) program should be easy enough. Thanks.

  • evanhevanh Posts: 15,126

    Yes, but get it from CLKMODE, the symbol, not hardcoded address $40.

    The masking part is just more reliability assurance. The mode word could contain those bits set, and it's important they not be at that step.

  • Yeah and here lies the problem in knowing the old mode.

    Since your loader is in Spin you might do clockset to RCFAST in Spin after loading your image and before starting your PASM cog to copy and start.

    Easy Peasy, without worry.

    Mike

  • @evanh said:
    Yes, but get it from CLKMODE, the symbol, not hardcoded address $40.

    The masking part is just more reliability assurance. The mode word could contain those bits set, and it's important they not be at that step.

    Oh, I see. Thanks!

  • @msrobots said:
    Yeah and here lies the problem in knowing the old mode.

    Since your loader is in Spin you might do clockset to RCFAST in Spin after loading your image and before starting your PASM cog to copy and start.

    Hey, Mike! Did you step out of your man-cave construction zone to come up for air? Anyway, why "might" I "do a clockset to RCFAST" right before calling my PASM? I guess I could, but I probably won't, right?

  • evanhevanh Posts: 15,126

    I think Mike is happy and just voicing his agreement with the second paragraph. First paragraph will be referring to the alternative of CLKMODE handover.

  • evanhevanh Posts: 15,126

    Early on, there was some big discussions, that I helped fuel O_o, around getting agreement on how to do CLKMODE handover with mailboxes.

    I think it might have been Eric that proposed RCFAST handover as the solution. I remember I liked it immediately anyway.

  • @evanh said:
    Answer[6]: Aside from a hard reset, hub-ops are only initiated by cogs. HUBSET instruction manipulates some special hardware registers that are truly in the hub. In the case of system clock, there is 25 flip-flops forming the mode bits of the clock mode register. There is only one of each hub register and they will share a common bus between all cogs. Which is why each cog's hub-ops are enforced into interleaving time slots.

    There is other parts of the prop2 that do have their own processing:

    • The FIFOs, timing wise, are relatively independent of the cogs and do modify hubRAM. They depend on their respective cog for direction but access hubRAM at their own pace and are bound to slot timing like the hub-ops are.
    • Streamers, which heavily use the FIFOs, are part of the cogs but also run in parallel and pace themselves once set going.
    • The 64 smartpins each do their own thing independent of all else, although they do nothing by default and never interact with hubRAM.
    • The cordic is a hub resource. It can accept a new command on every clock tick but this is time sliced between all cogs. So all the instructions for cordic-ops, except maybe GETQX/Y, have the slot timing effect. The cordic runs in parallel to the cogs while it has any command in its pipeline.

    In Spin2 (before calling pasm), I did this (for better or worse:

    'D= %0010_xxxx_xxxx_xxLW_DDDD_DDDD_DDDD_DDDD 'Last 16KB of RAM and 166 Debug Interrupts for Cogs
    hubset(%0010_0000_0000_0000_0000_0000_0000_0000) 'L=0=don't lock W&D; D=0=disable debug interupt

    Oh, and I did a pinclear.

    I probably need to think about your list above one-by-one. I do want to read up on the Cordic to see if any new commands in the new program will overwrite any old result, or if the Cordic will block. Also, today, I saw something about Q that I want to re-read. Need to think about the streamer, too (and maybe the fifo), although it seems likely that the programs that I file boot will be reusing these similarly to how the prior program was using them.

    What happens when a cog stops? Does all the data in it remain in place? And what about it's PC and wr? Anyway, there's no way for me to try to clear any of that stuff, I don't guess. I mean, cogstop kills the cog forever, right, until it get reloaded. I mean, it's not like it's paused, right? There's no way to have it pick up from where it last left off on a cogstop. That is, it's not like doing a waitx. I guess everything gets reset when I launch a cog, so I don't need to worry about any of that (not sure about cog pairing, though). Also, I wonder if I can ignore the digital filters (seems likely).

    Oh, I wonder if a new Edge with a crystal oscillator will change any of this.

  • @evanh said:
    Early on, there was some big discussions, that I helped fuel O_o, around getting agreement on how to do CLKMODE handover with mailboxes.

    I think it might have been Eric that proposed RCFAST handover as the solution. I remember I liked it immediately anyway.

    Without you guys for Chip to bounce things off of, where would we (and the P2) be? At least, it is stronger with all the input from you guys.

  • My thinking is that doing the clockset to RCFAST in SPIN will take care of being compiled in PropTool or Flexprop and you do not need to do in in PASM in the COG.

    Load the image into upper HUB, set clock to RCFAST in SPIN, then run your 'copy and start COG' already in RCFAST. Handover will be fine.

    And you already have the PASM code to do so.

    Mike

  • @msrobots: I'll need to think about that (have to walk the dog soon and I've been up all night and not thinking so straight, assuming that I ever do). But if I do that RCFAST thing, I'd want to do it through the safe clkset() method, I suppose. And it would seem (without calculating) that using RCFAST could add maybe a half second to the file booting process, though that's probably no biggie (big deal), I guess.

  • Anyway, you folks have been great. When I came back from my last walk with my dog (which lasted about two hours), Wuerfel_21 had already tutored me in writing pasm (which I have now applied). And now you guys have schooled me in how to do a proper handover (or whatever you want to call it). Thanks so much!!! Apologies for monopolizing so much of your time.

  • evanhevanh Posts: 15,126
    edited 2021-07-09 02:14

    Oh, that's right. The reference code for handover also included a 5 ms delay before COGINIT, after RCFAST is set. This allows the crystal oscillator time to properly shutdown. I'm not sure how important it actually is to ensure that but, for sure, the first thing the new program will likely do is start it back up again.

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 02:24

    Okay, well whatever code I try, I learned a couple of hours ago that I need to do the file boot at least 10 times in a row in order to make sure that it is (relatively) stable. Because sometimes the clock will work, and sometimes it will glitch if one doesn't do things properly (and I wasn't doing things properly).

  • evanhevanh Posts: 15,126
    edited 2021-07-09 02:48

    @JRetSapDoog said:
    In Spin2 (before calling pasm), I did this (for better or worse:

    'D= %0010_xxxx_xxxx_xxLW_DDDD_DDDD_DDDD_DDDD 'Last 16KB of RAM and 166 Debug Interrupts for Cogs
    hubset(%0010_0000_0000_0000_0000_0000_0000_0000) 'L=0=don't lock W&D; D=0=disable debug interupt

    Good idea. That'll ensure back to default.

    Oh, and I did a pinclear.

    You'll want to do two, one for each 32 pin bank, A and B. ie:

        PINCLEAR( $1f<<6 )
        PINCLEAR( $20 | $1f<<6 )
    

    What happens when a cog stops? Does all the data in it remain in place? And what about it's PC and wr? Anyway, there's no way for me to try to clear any of that stuff, I don't guess. I mean, cogstop kills the cog forever, right, until it get reloaded. I mean, it's not like it's paused, right? There's no way to have it pick up from where it last left off on a cogstop. That is, it's not like doing a waitx. I guess everything gets reset when I launch a cog, so I don't need to worry about any of that (not sure about cog pairing, though). Also, I wonder if I can ignore the digital filters (seems likely).

    That has been asked before. I don't remember what Chip's answer was. I suspect COGINIT erases cogRAM. COGINIT always overwrites cogRAM. Hmm, COGINIT can jump straight to hubexec in hubRAM. All special registers, eg: DIRA[31:0], are cleared on COGSTOP, and also on a hard reset.

    Oh, I wonder if a new Edge with a crystal oscillator will change any of this.

    The %CC bits in the clock mode will be %01 instead of %10. It'll be a 20 MHz oscillator so everything else will be the same.

  • evanhevanh Posts: 15,126

    @JRetSapDoog said:
    Okay, well whatever code I try, I learned a couple of hours ago that I need to do the file boot at least 10 times in a row in order to make sure that it is (relatively) stable. Because sometimes the clock will work, and sometimes it will glitch if one doesn't do things properly (and I wasn't doing things properly).

    That brings back memories. :O

  • @evanh said:
    That has been asked before. I don't remember what Chip's answer was. I suspect COGINIT erases cogRAM. COGINIT always overwrites cogRAM. Hmm, COGINIT can jump straight to hubexec in hubRAM. All special registers, eg: DIRA[31:0], are cleared on COGSTOP, and also on a hard reset.

    Glad you corrected that. A previously loaded cog can also be started in cogexec and lutexec, and not necessarily at address 0.

    For Jim's purposes, a stopped cog will have its FIFO and streamer stopped, and sticking to a (standard) COGINIT with the D field holding a value less than 31 shouldn't require any further clearing of state.
    The PINCLEARs will reset all the smartpins. If the launched program needs any smartpin functions then it will need to set them up itself.
    The CORDIC will continue without stalling, and any operations that were in flight when the cog was stopped will complete within 55 clocks, with only the last result pair for each cog being available to be read. No program should rely on any result of a GETQX/GETQY if it hasn't previously started a CORDIC operation, so there's nothing to clear there.
    Digital Filters can be ignored, because any program that uses them should set them first.

    An ambitious approach would be to have each launchable program have a header to indicate which facilities to reset or launch prior to launching the main program. That could allow a modular system to have elements 'pre-launched' if they are common between programs, and reduce the setup overhead for each main program. That is moving into OS territory.

  • evanhevanh Posts: 15,126

    He might be wanting replicate power up defaults.

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 17:10

    @AJL: Thanks so much for your comments about the FIFOs, streamers, the two pinclear() calls, the CORDIC and the digital filters. That gives me more confidence that, after the handover, the state of the P2 system will be pretty similar to (or similar enough to) its state after a boot from the ROM. I say "pretty similar" because I don't think I care about things like total elapsed time since bootup. Your comment here and earlier is much appreciated.

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 17:16

    I probably should (and I might = never say never), but I'm afraid that it would cause my brain to suffer a thermal meltdown. At this point, I really have a hard time understanding code from you expert users with experience in the uC field (I'm just a hobbyist), but I'm learning. Still, I appreciate your willingness to share. I think it was you that said that you had produced a commented version of the interpreter, and that's what I'd need if I were to make any sense of it at all. I'm sure that you've commented your own code, too, but, at this point, I just want to keep making incremental progress. I'll be somewhat busy this weekend, but next week, maybe I can start to work on a menu program. If I get that up and running, I might feel more inclined to start looking at other people's code. It's a real shame that I have a hard time, at this point, anyway, in understanding other people's code because I know that is how you guys learn and one of the best ways (and I do wish that there was a cookbook with simple examples). But I kind of need to get a project under my belt first (learn myself by doing), and then maybe I'll be able to start looking at code from you guys and adopting your style, things like 0_0 instead of a 0 when the value will be replaced on the fly for example. Also, I'm not at all looking at doing an OS (that's 10 levels above my paygrade), despite a few similarities to booting various games off of an SD card. Still, having said all that, if you feel that I'm really missing something, then feel free to lead me to water and force me to drink. BTW, I can see how an operating system would benefit by using, for example, a faster way to copy code than I'm using, but for my limited purpose, what I'm doing is easy to understand and should be fine (at least for now).

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 17:42

    @tritonium said:
    Hi

    Quite agree- not being able to run p2 programs loaded from an SD card attached to that P2 is a real show stopper- it limits its use in so many ways- in my humble opinion.

    Dave

    Thanks for your comment, tritonium. It would be nice if one could execute one instruction and get the P2 system back to the same state or a very similar state to that which it has after a real boot (not a so-called file boot). However, it seems like we can get pretty close to that without much trouble (once one knows what steps to take). So fortunately, there shouldn't be any limit as such. I'm glad this ability is also important to others on the forum, like you. Thanks for posting.

  • JRetSapDoogJRetSapDoog Posts: 954
    edited 2021-07-09 17:55

    @evanh said:
    Yes, but get it from CLKMODE, the symbol, not hardcoded address $40.

    The masking part is just more reliability assurance. The mode word could contain those bits set, and it's important they not be at that step.

    This is to evanh and anyone else who cares to comment: I just did a little experimenting, and I'm a bit confused about what symbol I should be using, but below is what I did (I stuck with pasm for this just because it should allow file booting a bit faster):

                      'Note: copying upper hub to lower hub code and killing cog code omitted for brevity
    
                      'rdlong  cm0, #@clkmode     'for tesing (remove later)
    
                      'clear the upper half of hub (now that it has been copied to lower half)
                      setq    ##65_536-1        'use setq to do a "fast block" clear for 65536 longs
                      wrlong  #0,   ##262_144   'zero out the upper half of the hub a long at a time
    
                      'Stop all other cogs (whether extant and active or not)
                      cogid   kid               'get cog (kog) id
                      mov     tmp,  #15         'highest possible cog number (on a future 16-cog P2 variant)
    .kill             cmp     tmp,  kid  wz     'don't stop the current cog
            if_nz     cogstop tmp               'stop all but the current cog
                      djnf    tmp,  #.kill
    
                      'Use RCFAST before doing "handover" to new (file booted) program via a coginit
                      'hubset ##%0000_000E_DDDD_DDMM_MMMM_MMMM_PPPP_CCSS 'set clock mode
                      'Pg. 57 of Silicon: "The four LSBs are all that are needed to switch among clock sources..."
                      mov     cm1,  ##clkmode_  'clkmode_ before RCFAST for testing (remove later)
                      hubset  #$F0              'set 20 MHz+ (RCFAST) mode; PPPP=1111; CCSS=0000
                      mov     cm2,  ##clkmode_  'clkmode_ after RCFAST, for testing (remove later)
                      hubset  ##clkmode_ & !3   'zero SS clock source bits (inhibits PLL/foreces RCFAST mode)
                      waitx   ##20_000_000/100   'wait ~10ms (50ns x 200k = 0.01 sec)
    
                      'load program from beginning of hub into cog 0 and start it
                      cmp     cm1,  cm2  wz     'compare two clkmode_ readings for testing (remove later)
            if_z      coginit #0, #0            'start new program in cog 0  <--remove if_z after testing
    
                      'kill the current cog
                      cogid   tmp               'get the current cog's ID
                      cogstop tmp               'stop the current cog
    
    cm0     res   1   'for use with rdlong cm0, #@clkmode at start of pasm
    cm1     res   1   'clockmode_ symbol before changing to RCFAST
    cm2     res   1   'clockmode_ symbol after changing to RCFAST
    

    I used the clkmode_ symbol with the underscore, but I'm not sure if that's correct. I also did an equality comparison of its content with #@clkmode, and it seems to be the same BEFORE copying the upper hub down but not AFTER. I'm not sure why. Maybe those hub $40 & $44 locations don't get set until after the interpreter runs.

    Anyway, this is what I "learned" (if that's the right word). Note that in the code above, the code involving cm0, cm1 and cm2 is just for testing and will be removed later. But for the following main instructions:

                      hubset  #$F0              'set 20 MHz+ (RCFAST) mode; PPPP=1111; CCSS=0000
                      hubset  ##clkmode_ & !3   'zero SS clock source bits (inhibits PLL/foreces RCFAST mode)
                      waitx   ##20_000_000/100   'wait ~10ms (50ns x 200k = 0.01 sec)
    

    this file booted fine 13 times in a row (plus a bunch of other times). So I tried commenting out lines:

    [1] With hubset $#F0 commented out: 13 successes, 0 failures
    [2] With waitx commented out, same: 13 successes, 0 failures
    [3] With hubset ##clkmode_, & !3 commented out: only 7 successes and 6 failures.
    And there was no particular order, such as alternating.

    BTW, when I say "successes," I just mean that I file booted to another program okay, not that things are being handled properly.

    I was just slightly concerned that doing a hubset #$F0 might change the clkmode_ symbol's content, so I added the little before and after test, but it didn't seem to change anything (that is, pasm just executes the hubset instruction but doesn't apparently go and change clkmode_, as I suppose that's under Spin2's jurisdiction).

    That's all I've tested so far. I thought about using wrlong with #@clkmode, but didn't (see the need).

    Anyone feel free to correct me if I'm on the wrong track with the above three instructions to get into RCFAST mode for the handover. As for commenting out the waitx not adversely affecting file booting, it also didn't hurt it when it was in place, so I think I'll keep it. It's probably just there for when you immediately change to a new PLL setting in the next instruction, which I'm not doing here, so it could probably be omitted, but I'll keep it for now.

    As for commenting out the hubset #$F0 line, although it file booted okay without it, I worry that it might not give the proper RCFAST clock setting to the new program that runs after coginit. So I'll keep that, too.

    BTW, if I should be passing clkmode in to this pasm routine, let me know, but it seems like it already has access (maybe in a couple of ways??).

  • evanhevanh Posts: 15,126

    @JRetSapDoog said:
    This is to evanh and anyone else who cares to comment: I just did a little experimenting, and I'm a bit confused about what symbol I should be using, but below is what I did (I stuck with pasm for this just because it should allow file booting a bit faster):

    Oh, I've been constantly surprised throughout this topic. I was very much under the impression you were using Spin. Which is why I didn't try pushing the assembly details earlier.

    The CLKMODE variable doesn't exist in pure Pasm builds. So no symbol is generated for it either. On the up side you can just make up any location for your temporary copy of the clock mode. It doesn't have to even be in hubRAM because when it comes to handover you've set the Prop2 back to RCFAST after all.

  • evanhevanh Posts: 15,126
    edited 2021-07-10 00:06

    @JRetSapDoog said:

                      hubset  #$F0              'set 20 MHz+ (RCFAST) mode; PPPP=1111; CCSS=0000
                      hubset  ##clkmode_ & !3   'zero SS clock source bits (inhibits PLL/foreces RCFAST mode)
                      waitx   ##20_000_000/100   'wait ~10ms (50ns x 200k = 0.01 sec)
    

    this file booted fine 13 times in a row (plus a bunch of other times). So I tried commenting out lines:

    [1] With hubset $#F0 commented out: 13 successes, 0 failures
    [2] With waitx commented out, same: 13 successes, 0 failures
    [3] With hubset ##clkmode_, & !3 commented out: only 7 successes and 6 failures.
    And there was no particular order, such as alternating.

    For a quick experiment, try this in that same test (It's the alternative to known prior mode):

                      hubset  #$F0              'set 20 MHz+ (RCFAST) mode; PPPP=1111; CCSS=0000
                      hubset  #0
                      waitx   ##20_000_000/100   'wait ~10ms (50ns x 200k = 0.01 sec)
    

    As for commenting out the hubset #$F0 line, although it file booted okay without it, I worry that it might not give the proper RCFAST clock setting to the new program that runs after coginit. So I'll keep that, too.

    That is an alternative, non-ideal, solution to the using of prior clock mode. Either-Or. It relies on a discovered bias that Chip wasn't confident would always behave that way in every Prop2 die. Don't use #$F0 when prior mode can be known.

  • AribaAriba Posts: 2,682

    I also have made a similar bootfile methode for FSRW. The program that wants to launch another bin (bix) file has to pass a hub address to the methode, where the new file can be loaded (free hub behind the current program or a screenbuffer or something else).
    I load the new code there, then copy it to hubaddr 0 in a inline PASM2 loop and start a cog with it.
    I stop other running cogs before, but I don't change pin states or the clock mode. When you launch the new program the clock is anyway set new. And sometimes it's better to not disable pins, they can have pullups set, or are in a smartpin mode, that is necessary. I think the application that starts the new program should decide which pins can be set to input, before it starts the new code.

    Inline PASM between ORG ... END gets copied to cog ram and then executed in the cog, so you don't need to start a cog just for the PASM part. This works also for FlexSpin.

    Andy

Sign In or Register to comment.