Shop OBEX P1 Docs P2 Docs Learn Events
passing arguments to P2 programs — Parallax Forums

passing arguments to P2 programs

flexspin supports CHAIN to start one program from another, but at the moment there's no defined way to pass data from the parent to the child. The obvious solution is to reserve a block of memory at the top of RAM and put the passed data there.

This seems like a place where having a standard of some sort would be useful. @Cluso99 , I assume you'll be doing something similar for your OS, and perhaps others will want to do it as well.

A simple standard might be to just say there's 256 bytes (or whatever size) just under the DEBUG area and that command line arguments for the new program will be placed there. This could be done WIndows style (just a 0 terminated ASCII string) or Unix style (an array of pointers to 0 terminated strings). The Windows style might be simpler, although it means parsing file names enclosed in quotes to allow strings in them... not a huge problem for SD cards (where you're not likely to have spaces in file names) but might be an issue for the host file system on the PC. Unix style would be more flexible but is conceptually trickier.

This same mechanism could be used by loadp2 to give arguments to the loaded program, so you could for example pass parameters to test programs. Or even better, give a file name to a flash / sd card copy program, so the P2 program can stream data from the host and write it to flash or to SD. This would get around the limitations of the current flash programmer in flexprop (where the data has to fit into memory).

Thoughts?

Comments

  • I've been thinking about ways to pass data into programs.
    My approach would be a lot more complex for the loader, but really simple for the program itself. That is to store alongside the binary a list of addresses where the loader would patch in the runtime data. This could be shell arguments, but also pin assignments, video modes, etc.
    I guess it would be a superset of your proposal.

    You certainly want to avoid reading garbage as arguments, so I'd put a "magic value" up there, too. If this is not found, there are no arguments. The argument handling code would also erase it after it is done, so it doesn't mess stuff up if another program is loaded without clearing the area first.

  • @ersmith said:
    This same mechanism could be used by loadp2 to give arguments to the loaded program, so you could for example pass parameters to test programs. Or even better, give a file name to a flash / sd card copy program, so the P2 program can stream data from the host and write it to flash or to SD. This would get around the limitations of the current flash programmer in flexprop (where the data has to fit into memory).

    Thoughts?

    I like the sound of having FlexProp pass startup arguments in, and I can see some benefits for controlling debugging, automating etc, without needing to necessarily build in a serial interpreter when some startup arguments change. Also I like the idea it can be used for filenames, or memory addresses etc. The scheme itself sounds reasonable, and high memory is probably the best place for it, but not all cases will always use the DEBUG area. I guess you need to assume it will be. Any decrementing type stack applications will need to be adjusted accordingly and be aware of this. It might be good to have the first value (highest memory long) define the length of this reserved area too, in case it needs to be over 256 bytes one day. Or even better maybe the final long value can just be a pointer to where this null terminated string begins, and 0 if unused. We can think of it as either an environment string area available at boot time or for command/startup arguments during chaining etc.

  • Cluso99Cluso99 Posts: 18,069

    I am currently passing parameters to other programs/cogs in my formatter to the drivers which reside in other cog(s). I just pass a hub address of a parameter list via PTRA when the cog starts. This hub list contains as it's first parameter, another hub address where a big buffer resides. More parameters include I/O pins like an SD card's pins, a serial's pins, a vga's pins, any config data such as baud, etc.

    Now for my OS, it will use just below the 16KB which actually means 512KB-16KB = just below the 496KB = just below $7C000. I will use, as I did with P1, an object file which is only a set of CON declarations with equates to hub addresses. This gets added as an object in every program (ie a binary) compiled. Now, of course, each cog needs to know where its' info resides. I gave each cog a set of 4 longs. You can do a lot with 4 longs, including using it as a single character buffer, or a buffer control. The data can depend on the type of program running in the cog, or it can be generic.

    Currently my P2 drivers (multiportserial, SD, LCD, and coming VGA and Keyboard) all operate totally independantly, save for a parameter list which is passed as a hub address when the program (cog) starts. Each driver also has a buffer for transmit and a buffer for receive (if only transmit or receive then only one buffer), with the appropriate 4 long list(s) head, tail, start and end with the address of this list being passed in the main parameter list. It is currently working well. I have 16 slots (ie 16 buffers, and 16 pointer lists of head/tail/start/end) assigned, and they get allocated as required.

  • OK, I'll make a proposal then: that we reserve the top 4 longs $7BFF0 - $7BFFF for "command line" parameters, as follows:

    $7BFF0: magic value $56475241 ("ARGV"); if present indicates that the remaining 3 longs are valid
    $7BFF4: number of arguments (integer)
    $7BFF8: pointer to list of arguments in HUB memory
    $7BFFC: reserved (set to 0 for now)
    

    The pointer at $7BFF8 gives where the command line arguments really are. This is a series of zero terminated strings, one after the other. The total number of strings is indicated by the long at $7BFF4 and (for now) must be in the range 0-$FF. So for example to pass two file names FLASH1.BIN and FLASH2.BIN to a format program the memory would contain bytes like the Spin2 DAT declaration:

    myargs byte "FLASH1.BIN", 0, "FLASH2.BIN", 0
    

    and the memory at $7BFF0 would contain 4 longs:

    long $56475241 ' magic value
    long 2 ' number of arguments
    long @@@myargs ' pointer to actual arguments
    long 0
    

    Typically the arguments themselves (the actual strings) would also go in HUB memory up near $7BF00, but with this scheme we don't have to force that.

  • TonyB_TonyB_ Posts: 2,127
    edited 2021-02-24 11:44

    @ersmith said:
    OK, I'll make a proposal then: that we reserve the top 4 longs $7BFF0 - $7BFFF for "command line" parameters, as follows:

    $7BFF0: magic value $56475241 ("ARGV"); if present indicates that the remaining 3 longs are valid
    $7BFF4: number of arguments (integer)
    $7BFF8: pointer to list of arguments in HUB memory
    $7BFFC: reserved (set to 0 for now)
    

    The ideal place for CGA-compatible video RAM is the 16K from $78000-7BFFF and I think it should not be anywhere else.

    Would your proposal clash with CGA data in the top text page?

  • Cluso99Cluso99 Posts: 18,069
    edited 2021-02-24 12:04

    Eric,
    Finally someone else is thinking about this :smiley:
    Don't know how many times I've tried.

    May I suggest going a little further and allocate 8 longs to start with...

    $7BFFC: _HubFree:  stores total hub available (ie >= is used by the OS)  (eg $7B000 means $0000-$7AFFF is available) In this eg it would be $7BFE0
    $7BFF8: pointer to list of arguments in HUB memory
    $7BFF4: number of arguments (integer)
    $7BFF0: -reserved- possibly for an OS pointer
    $7BFEC: -reserved- possibly for a COG table
    $7BFE8: _OS_Clkfreq:  clkfreq(Hz): saved fm hub long $00044
    $7BFE4: _OS_Clkmode:  clkmode:     saved fm hub byte $00040  
    $7BFE0: magic value $56475241 ("ARGV"); if present indicates that the remaining 7 longs are valid
    

    FWIW I didn't fine any need to pass the number of arguments between programs as I just pulled the args as needed from the buffer. So my buffer contained what was entered, less what had already been removed and actioned.

    Just for reference, here is what I modelled almost 2 years ago, based on what I did for P1. Of course the upper 16KB is no longer available normally.

    '' +--------------------------------------------------------------------------+
      _hub          = $fc400            ' base of serial monitor hub code
    '' +--------------------------------------------------------------------------+
    ' OS2 Hub Definitions...         
    ' -------------------          bytes
      _OS_Clkfreq   = _hub + $00  '    4     ' clkfreq(Hz): saved fm hub long $00044
      _OS_Clkmode   = _hub + $04  '    4     ' clkmode:    saved fm hub byte $00040
      _SDpins       = _hub + $08  '    4     ' \ sd pins packed 4 bytes
                                  '          ' / Byte 3=/CS, 2=CLK, 1=MOSI, 0=MISO
      _SIOpins      = _hub + $0c  '    4     ' \ serial pins and mode settings (and cog#)
                                  '          ' / Byte 3=cog, 2=mode, 1=SI, 0=SO
      _SIObaud      = _hub + $10  '    4     ' serial baud (speed typ 115,200)
    
      _OS_Rows      = _hub + $14  '    1     ' \ combined <lf> and rows
        _LF_MASK      = $80                  ' | b7  : 1= <lf> ON; 0= strip <lf>
        _ROW_MASK     = $7F                  ' / b0-6: no of rows on screen (0-127)
      _OS_Columns   = _hub + $15  '    1     '         no of cols on screen (0-255)
      _OS_Cogs      = _hub + $16  '    1     ' stay resident cogs: 1= don't stop on reboot
      _OS_sparebyte = _hub + $17  '    1     '
    
    ' _OS_spare1    = _hub + $18  '    4     '
    ' _OS_spare2    = _hub + $1c  '    4     '
    
      _AuxIn        = _hub + $20  '    4     ' auxilary input  rendezvous
      _AuxOut       = _hub + $24  '    4     ' auxilary output rendezvous
      _StdIn        = _hub + $28  '    4     ' standard input  rendezvous
      _StdOut       = _hub + $2c  '    4     ' standard output rendezvous
    
    '  _pBuffer_C    = _hub + $030  '   16  '| '   user buffers... 
    '  _pBuffer      = _hub + $040  '  128  '| ' \ ...joins 2 buffers A+B
    '  _pBuffer_A    = _hub + $040  '   64  '| ' |   (used to pass parameters between modules)
    '  _pBuffer_B    = _hub + $080  '   64  '| ' /   (maybe serial in and serial out buffers?)
    '' +--------------------------------------------------------------------------+
    

    And here is what I use for my P1 OS

    ' OS Hub Definitions...         
    ' ------------------       bytes
      _HubFree      = $7FFC  '    4     ' \ stores total hub available (typ $7800)
                                        ' |  (hub is allocated to the OS above this value)
                                        ' /  (eg $7000 means $0000-$6FFF is available)
    
      _OS_DateTime  = $7FF8  '    4     'Year20xx  Month    Date    Hours   Minutes   Seconds
                                        ' (00-63)  (1-12)  (1-31)  (00-23)  (00-59)   (00-59)                                     
                                        '  000000___0000____00000___00000____000000____000000
                                        'To convert to FAT16/32 format, shift >>1 then add 16<<25
                                        '   --> Y(7)M(4)D(5)H(5)M(6)S*2(5bits) Base=1980
                                        '  (FYI seconds in 4yrs = 126,230,400)
    
      _OS_Rows      = $7FF7  '    1     ' \ combined <lf> and rows
        _LF_MASK      = $80             ' | b7  : 1= <lf> ON; 0= strip <lf>
        _ROW_MASK     = $7F             ' / b0-6: no of rows on screen (0-127)
      _OS_Columns   = $7FF6  '    1     '         no of cols on screen (0-255)
      _OS_Cogs      = $7FF5  '    1     ' stay resident cogs: 1= don't stop on reboot
      _OS_Clkmode   = $7FF4  '    1     ' clkmode: saved fm hub byte $0004
    
      _OS_Clkfreq   = $7FF0  '    4     ' clkfreq(Hz): saved fm hub long $0000
    
    
      _SDpins       = $7FEC  '    4     ' \ sd pins packed 4 bytes
                             '          ' / Byte 3=/CS, 2=DI, 1=CLK, 0=DO
      _SIOpins      = $7FE8  '    4     ' \ serial pins and mode settings (and cog#)
                             '          ' / Byte 3=cog, 2=mode, 1=SI, 0=SO
      _SIObaud      = $7FE4  '    4     ' serial baud (speed typ 115,200)
    
      _Hardware     = $7FE0  '    4     ' \ hardware: hi-word=company, lo-word=config
                                        ' |            $0001 = Cluso99  $0001 = RamBlade 1           
                                        ' |            $0001 = Cluso99  $0002 = TriBlade#2           
                                        ' |            $0001 = Cluso99  $0003 = RamBlade3
                                        ' |            $0001 = Cluso99  $0004 = P8XBlade2
                                        ' /            $0001 = Cluso99  $0007 = CpuBlade7
                                        ' ^^^ may be more valuable for something else??
    
      _AuxIn        = $7FDC  '    4     ' auxilary input  rendezvous
      _AuxOut       = $7FD8  '    4     ' auxilary output rendezvous
      _StdIn        = $7FD4  '    4     ' standard input  rendezvous
      _StdOut       = $7FD0  '    4     ' standard output rendezvous
    
      _CIDRegister  = $7FC0  '   16     ' \ CID (card identification register)
      _CSDRegister  = $7FB0 '    16     ' | CSD (card specification data register)
      _CIDcopyAddr  = $7FAC  '    4     ' | address of CIDcopy
      _SDblockAddr  = $7FA8  '    4     ' | address of Block
      _SDsectorAddr = $7FA4  '    4     ' | address of Sector
      _SDflags      = $7FA3 '     1     ' | (WPflag)<<4 | (NoCard) 0==OK  (for later!!!
      _SDlockcogid  = $7FA2  '    1     ' | (LockID+1)<<4 | (CogID+1)
      _SDerror      = $7FA1  '    1     ' | error   (returned from pasm driver)
      _SDcommand    = $7FA0  '    1     ' / command (set by app, cleared by pasm driver)
    
      _OSreserved   = $7F90  '   16     ' undefined
    
      _pBuffer_C    = $7F80  '   16  '| ' \ user buffers... 
      _pBuffer_B    = $7F40  '   64  '| ' |   (maybe serial in and serial out buffers?)
      _pBuffer_A    = $7F00  '   64  '| ' /   (used to pass parameters between modules)
      _pBuffer      = $7F00  '  144  '^ ' / ...joins all 3 buffers A+B+C
    
    {{
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    'required for "compile" using old sdspiq
      _SDSPI        = $7F00       - 3 * 4    '3 rendezvous variables \ fsrw routines
      _SXFS2        = _SDSPI      - 4 * 4    '4 rendezvous variables |
      _SXFS         = _SXFS2      - 4 * 4    '4 rendezvous variables |
      _SDbuffer     = _SXFS       - 512      'buffer                 /
    'Currently ALL the following is position dependant (for older compatibility)
      SDSPIRENDEZVOUS   = _SDSPI             '3 rendezvous variables \ fsrw routines
      SXFS2RENDEZVOUS   = _SXFS2             '4 rendezvous variables |
      SXFSRENDEZVOUS    = _SXFS              '4 rendezvous variables |
      METADATABUFFER    = _SDbuffer          'buffer                 /
    
      _HUB_RESERVED = _SDbuffer         ' $7?00-$7FFF currently reserved by the OS
    '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }}
    
    {{------------------------------------------------------------------------------
    '' RR20160208 removed until required...                         
    
      _pCogTables   = $7E00  '  256     ' \ 8*32B cog usage tables
                                        ' | TBD
                                        ' |   Current thinking is...
                                        ' |     1 byte for "type"
                                        ' |     1 long for sector address to retrieve filename
                                        ' |   However, could also be used as 2*16byte buffers
                                        ' /     with the head+tail(s) kept in _StdIn & _StdOut
    
      _pSectorBuf   = $7C00  '  512     ' SD card i/o buffer                 
      _pSpinVector  = $7800  ' 1024     ' vector table for Cluso's faster spin interpreter
    
      _HUB_RESERVED = $7800             ' $7800-$7FFF currently reserved by the OS
      _HUB_RAMSIZE  = $8000             ' Total hub ram 
    
      _pSectorBuf   = $7C00  '  512     ' SD card i/o buffer                 
      _pSpinVector  = $7800  ' 1024     ' vector table for Cluso's faster spin interpreter
    ------------------------------------------------------------------------------}}                         
    
      _HUB_RESERVED = _pBuffer          ' $7F00-$7FFF currently reserved by the OS
      _HUB_RAMSIZE  = $8000             ' Total hub ram 
    
    
  • RaymanRayman Posts: 13,897

    Intersting... I was thinking that the bottom of RAM would be the place to do this. But, I don't know exactly how all this works...

    Doesn't flexprop start loading a program at $400?

  • @TonyB_ said:

    @ersmith said:
    OK, I'll make a proposal then: that we reserve the top 4 longs $7BFF0 - $7BFFF for "command line" parameters, as follows:

    $7BFF0: magic value $56475241 ("ARGV"); if present indicates that the remaining 3 longs are valid
    $7BFF4: number of arguments (integer)
    $7BFF8: pointer to list of arguments in HUB memory
    $7BFFC: reserved (set to 0 for now)
    

    The ideal place for CGA-compatible video RAM is the 16K from $78000-7BFFF and I think it should not be anywhere else.

    Would your proposal clash with CGA data in the top text page?

    What makes that 16K ideal for CGA compatible video RAM? Surely in real PCs the video RAM was at $B8000 rather than $78000, so no matter what we're already moving it.

  • @Cluso99 : Your 8 byte proposal seems fine to me as well. I had actually thought that we could walk down the memory starting at top of RAM and looking at magic numbers with different magic numbers for different things ("ARGV" for command line arguments, "OSIF" for OS info, "CLK_" for clock timing info, and so on) but that's probably more work than most people will want to take.
    The clock frequency and mode are already in RAM so I'm not so sure about copying them up there. OTOH there's a big problem with where those should be, which probably deserves another thread.

  • @Rayman said:
    Intersting... I was thinking that the bottom of RAM would be the place to do this. But, I don't know exactly how all this works...

    Doesn't flexprop start loading a program at $400?

    No, the default load location is $0.

  • In the last version of spinix I reserved 176 bytes at the high end of hub RAM to hold the calling parameters. This worked OK for passing parameters to, but it did limit the total size of the parameters. Also, this only allowed for a single instance of a program that could use these parameters. In other versions of spinix I would pack the parameter list and place it just before the stack/heap space. This allowed for multiple programs to run at the same time, each with their own space for the parameter list.

  • TonyB_TonyB_ Posts: 2,127
    edited 2021-02-24 18:57

    @ersmith said:

    @TonyB_ said:

    @ersmith said:
    OK, I'll make a proposal then: that we reserve the top 4 longs $7BFF0 - $7BFFF for "command line" parameters, as follows:

    $7BFF0: magic value $56475241 ("ARGV"); if present indicates that the remaining 3 longs are valid
    $7BFF4: number of arguments (integer)
    $7BFF8: pointer to list of arguments in HUB memory
    $7BFFC: reserved (set to 0 for now)
    

    The ideal place for CGA-compatible video RAM is the 16K from $78000-7BFFF and I think it should not be anywhere else.

    Would your proposal clash with CGA data in the top text page?

    What makes that 16K ideal for CGA compatible video RAM? Surely in real PCs the video RAM was at $B8000 rather than $78000, so no matter what we're already moving it.

    If we are talking about establishing standards, then what about a standard colour text mode and where to put its VRAM?

    The top 16K of hub RAM is out-of-bounds due to debugging and/or ROMification. Obvious next place is just below the top 16K. Note that the translation from $B8000 to $78000 is very simple.

    How should this text mode be done? CGA-style character code followed by attribute byte seems good. How much RAM to use? 16K allows for four 80x25 pages, or fewer but larger pages.

    Would this clash with your proposal? 80x25 needs 4000 bytes, not 4096, so the two could co-exist.

  • @TonyB_: I'm not sure I see any particular need for a CGA style graphics standard for P2. Many programs won't do video at all, and many of the ones that do will want higher resolutions than CGA provides, and/or will do pixel graphics rather than character based. In any case if your proposed 4000 byte buffer leaves 32 bytes free at the top of memory then it should co-exist fine with the argument passing stuff.

  • Cluso99Cluso99 Posts: 18,069

    I think we should also reserve a long for Xtal Frequency too.

Sign In or Register to comment.