Shop OBEX P1 Docs P2 Docs Learn Events
A request for help pulling a perfectly good object to bits! — Parallax Forums

A request for help pulling a perfectly good object to bits!

Dr_AculaDr_Acula Posts: 5,484
edited 2011-03-09 15:36 in Propeller 1
I was wonder if some Spin/PASM experts would mind casting their expert eye over the following code with a view to separating the Spin part from the PASM part.

This is with a view to creating self contained pasm code that can be loaded and reloaded many times by a program, and also with the idea of replacing the Spin part with Propbasic or C or any other language, but keeping the Pasm part the same, and also as a way of saving up to 14k of hub ram by loading the pasm part of cog code through the same 2k of hub ram.

I have pulled apart some simple code and now it is time to do something complicated, and for this task I have chosen to pull apart Tim Moore's multiple serial port object (Sorry Tim!). I believe this is the fullduplexserial object by Chip Gracey, modified by Tim Moore to run 4 ports, and then by Juergen Buchmueller to run two ports with bigger buffers. See attached.

Most of the pasm code will be unchanged. The Spin code will either stay the same, or be changed to Basic and thence to C via BCX. A large number of the lines of code will translate over ok.

Where I am a bit stuck is the memory model. Take for instance the variable rx_head0

Some objects in the obex (eg video drivers) declare variables in the spin code, often in a list, then exploit the fact that the compiler keeps these together, and then pass the first variable to the cog using PAR.

Things seem to be a little different here. I think what is happening is that there is a DAT section of code which sets aside some hub ram, then within that DAT section is both pasm code and some declarations of variables like rx_head0. The compiler puts this in a known section of hub ram, and then the spin code knows where this is and can reference it and change the values.

Is this a correct interpretation?

And if it is, then what would be the advantages and disadvantages of using this method compared with, say, using PAR?

More to the point, this might get really complicated when splitting up the code. Why split it up? Well, the spin/c/basic part can stay permanently in hub memory, and the pasm part can be loaded and reloaded through the same 2k block of hub ram, which has the potential to save 12k to 14k of hub ram if you applied this model to all the other cogs that are being loaded.

There is a block of code near the bottom:
'These are used by SPIN and assembler, using DAT rather than VAR
'so all COGs share this instance of the object
'
startfill
  cog                   long      0                   'cog flag/id

I guess what one could do is take all that and put it in an array. It could be a spin array, basic array or C array. The problem is that how do the rdlong and wrlong bits of code reference this? Do you pass the location of that array via a PAR and then do some maths internally in the cog? That might get tricky if that maths started taking up code space, as the cog is almost full (like pretty much all the cog code in the obex).

So I guess the question becomes - is there a way of telling cog code where its variables are within hub ram when the cog code has been compiled separately from the higher level language, and where the only way to pass the location of that code is via PAR?

Something like byte [@myarray][5] where the compiler condenses that down so there is no memory cost of adding the 5?

I hope that all makes sense!

Many thanks in advance.

Comments

  • Heater.Heater. Posts: 21,230
    edited 2011-03-09 04:38
    If you look in the latest version of Zog you will find a version of FullDuplexSerial that I have separated into separate PASM and Spin parts.
    The thing is still a single Spin file with the Spin and PASM in it but the assembled PASM binary blob is extracted when it is compiled. This is then used by C code.
    It should be in the libzog directory if I remember correctly.
    Might give you some ideas.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2011-03-09 15:36
    Thanks heater - I'll check that out.

    Comparing the 2006 FullDuplexSerial and Tim Moore's objects side by side, it appears there are some very fundamental differences about the way they work. Chip's driver has a VAR section at the beginning of the program which contains the buffers. I know from testing the compiler that these variables are going to stay together and I think get moved by the compiler to near the beginning of hub ram, along with other VAR sections the compiler collects.

    Tim Moore's object has all the buffers declared in the DAT section along with the cog code. There is an explanation in there about why this is, and I think it is so that some setup data can be kept in common if there are multiple instances of this object running. But this style of coding may not work at all well when trying to split the Spin and PASM code and where PASM code is being loaded from multiple objects through the same block of 2k hub ram. The buffers will get overwritten by the next cog to be loaded.

    I suspect there may be some saving in code space doing it that way. If you pass a list of variables through PAR, like Chip's code does, then you need to recreate those variables inside the cog. This is sometimes a little subtle to spot. An example in Chip's code is the spin part in the VAR section there is
    VAR
      long  rxtx_mode   
    

    and in the cog code, this gets translated to the cog variable
                            add     t1,#4                 'get rxtx_mode
                            rdlong  rxtxmode,t1
    

    where rxtxmode and rxtx_mode are not the same variable. Indeed, the former is a variable in cog, and the latter is a variable in hub.

    This means that splitting objects that use the PAR method is going to be a lot easier than splitting ones that use the 'common DAT' method.

    I can see some more memory savings here too. Not only could cogs be loaded through a common space in hub, but there are also variables in Spin that may only exist as temporary variables used to get data into a cog. Take the section of code in Chip's serial driver
    VAR
    
      long  cog                     'cog flag/id
    
      long  rx_head                 '9 contiguous longs
      long  rx_tail
      long  tx_head
      long  tx_tail
      long  rx_pin
      long  tx_pin
      long  rxtx_mode
      long  bit_ticks
      long  buffer_ptr
                         
      byte  rx_buffer[16]           'transmit and receive buffers
      byte  tx_buffer[16]  
    

    and take each of those variables and search for where else they occur. If they only ever occur in the Start section then they are temporary variables. So bit_ticks is a temporary variable and the space used for this could be recycled. rxtx_mode on the other hand is used in one other part of Spin code, so this needs to stay permanent.

    One could then reorder the PAR list to contain temporary and permanent variables, and recycle the space used by the temporary ones when the cog has loaded.

    This is a different way of looking at the way the propeller is programmed, but it could lead to some big memory savings, maybe doubling the available hub ram in some cases.

    I'm hoping also that it might lead to making more cogs available. Assume you are using all 8 cogs and you want to add a SD card driver. What you could do is put a message on the screen saying "Loading, please wait", clear the keyboard buffer, unload the keyboard driver, load the SD driver, access the SD card, then reload the keyboard driver.
Sign In or Register to comment.