Spin2

13468918

Comments

  • roglohrogloh Posts: 2,777
    edited 2020-01-16 - 02:04:07
    That could work too, and avoid the need to invent a macro syntax and processing for it.

    It might also be useful to have this object if you use it to maintain the pin's current state too.
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 02:15:31
    Maybe we just need some instructions like these, which consolidate WRPIN/WXPIN/WYPIN:

    WRXPIN(pin, mode, x)
    WRXYPIN(pin, mode, x, y)

    I need to review the modes to see how these ought to work.
  • roglohrogloh Posts: 2,777
    edited 2020-01-16 - 02:51:37
    I'm trying to get my head around the SPIN2 exit sequence. When a COG finally "returns", is there any way to pass the return value to the calling COG? Or is this something that is always needed to be done using some type of hub address mailbox being polled by a different COG?

    I guess my question is can a completing SPIN2 COG optionally return a result back synchronously somehow in the same COG by returning to some provided hub exec address passed in as an argument instead of only doing a COGSTOP and shutting down?

    I think this has been touched on before in the past and it might be useful to be able call a SPIN2 function from some other environment and return back to the original caller (which obviously will need its own cleanup/reloading of register state etc if the same COG is used by the caller). Maybe if some address argument is zero when launched it ultimately shuts down with COGSTOP, otherwise it can continue on with hub exec at that provided address and the stack can be used to return the result parameter from SPIN2?
  • roglohrogloh Posts: 2,777
    edited 2020-01-16 - 02:37:28
    In the above case it might also be handy to be able to launch SPIN2 without a COGINIT so the COG I/O state is preserved. I guess that could be done by setting things up appropriately before jumping directly to launch_spin instead of coginiting to it.
  • The ability for one program to load, run, and get a result back from a Spin program that is/has executed on another cog would be wonderful. Could a “mailbox” address to hold the result be passed to the Spin program at invocation?

    My use case is this: I’d love to “boot” a Spin “process” on an idle cog from FlexC, FlexASM, or FlexBASIC, and occasionally “check-back” for a result. This would allow me to access Spin functionality without needing to load it as a class.
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 03:16:24
    The way it is set up right now, when a Spin2 program ends, it stops its own cog. When launching a Spin2 program, though, you can pass it parameters. One of those parameters can be an address of a mailbox into which it deposits a final result before stopping itself.

    We would need to develop some scheme for having a cog load up the Spin2 interpreter, run some Spin2 code, and then return back to the caller in hub RAM. Actually, it could even return right to the cog's register memory. Registers $000..$15B are currently free.
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 03:21:34
    I reviewed all the smart pin modes and I see that we just need a single instruction to comprehensively configure any mode:

    CFGPIN(pin,mode,x,y)

    ...does this...

    FLTL pin
    WRPIN mode,pin
    WXPIN x,pin
    WYPIN Y,pin
    DRVL pin

    If WYPIN is not needed, just use 0 for the y parameter. No harm done.

    Remember that the pin parameter can express additional pins in bits 10..6. All those PASM instructions work that way. So, you could start up a whole bunch of DACs or PWMs with one instruction and then go set their individual output values, as needed.
  • roglohrogloh Posts: 2,777
    edited 2020-01-16 - 03:20:51
    Looking at launch_spin I think a lot of it is mostly there, if we can just return to some given hub exec code address when the SPIN2 code "returns", it could do different things like either write the result to some nominated mailbox/address before shutting down, or returning itself to its own caller in the same COG with results on some stack. If something is going to be possible one way or another I'm happy. It looks like the "stopcog" byte code address below is the key to this, if it can be patched to use something else before startup.

    I think having the ability to call SPIN2 code and get returned results from other environments is going to be great, even independent of whether it runs in different COGs or not, that's mainly just another optimisation to save a COG if it is going to be doing nothing useful while the SPIN2 code is running, though I see that in some cases preserving the IO pin state could be useful too if some IO work is done in one environment while other part are done in SPIN2 etc. This doesn't necessarily have to be a really fast interface, it's probably more for spawning tools and commands etc, so if a lot of COG/LUT state is saved/restored between these SPIN2 invocations when they are executed from the same COG as the caller, that might still work out okay in many cases.
    ' Launch Spin - runs via COGINIT
    '
    ' on entry:
    '
    '	ptra[0]  = pbase
    '	ptra[1]  = vbase | method<<20
    '	ptra[4+] = any parameters
    '
    ' on exit:
    '
    '	ptra[-4] = pbase | trap flag
    '	ptra[-3] = vbase
    '	ptra[-2] = dbase	@params...
    '	ptra[-1] = return (w)	@COGSTOP(COGID)
    '	ptra[ 0] = params...
    '
    launch_spin	setq	#2-1			'get pbase/vbase
    		rdlong	pbase,ptra
    
    		or	pbase,#%10		'set pbase 'trap' flag
    
    		mov	dbase,ptra		'set dbase to @params
    		add	dbase,#4*4
    
    		mov	w,#@stopcog		'set return to COGSTOP(COGID) bytecodes
    
    		setq	#4-1			'write pbase/vbase/dbase/w into stack
    		wrlong	pbase,ptra++
    
    		andn	pbase,#%11		'restore pbase address
    
    		setq	#cog_end-cog_code-1	'load cog code (overwrites dcall register)
    		rdlong	cog_code,#@cog_code
    
    		setq2	#$200-1			'load lut code
    		rdlong	$000,##@lut_code
    
    		mov	dcall,dbase		'set dcall (must be after loading cog code)
    
    		push	#wrf_rd			'return to wrf_rd to start xbyte after callinit
    
    		skip	##%111100000000_000_0	'begin bytecode execution of method in vbase[31:20]
    		jmp	#callinit
    
  • If you want to call some spin code from within spin, you only need to call it. It will return to you. Coming in from another language system is different, of course.
  • cgracey wrote: »
    I reviewed all the smart pin modes and I see that we just need a single instruction to comprehensively configure any mode:

    CFGPIN(pin,mode,x,y)

    Nice!

  • CFGPIN looks good Chip.

  • Some programming languages use SET and GET - as in SETPIN or GETPIN. So SETPIN would be CFGPIN, etc... and GETPIN would get the result value. Just a thought.
  • Cluso99Cluso99 Posts: 16,677
    edited 2020-01-16 - 07:32:21
    ozpropdev wrote: »
    CFGPIN looks good Chip.
    +1
  • PropGuy2 wrote: »
    Some programming languages use SET and GET - as in SETPIN or GETPIN. So SETPIN would be CFGPIN, etc... and GETPIN would get the result value. Just a thought.

    Pedward called tonight and we went over all these names. I think we made a big improvement:
    PINWRITE(pins,val)
    PINLOW(pins)
    PINHIGH(pins)
    PINTOGGLE(pins)
    PINFLOAT(pins)
    PINREAD(pins)
    PINMODE(pins,mode,xval,yval)
    

    I wasn't thinking so clearly, myself. I wanted shorter names. Turns out, we realized we could make first-4-letter aliases of all these names to keep code looking clean, if the programmer wants to use them:
    PINW(pins,val)
    PINL(pins)
    PINH(pins)
    PINT(pins)
    PINF(pins)
    PINR(pins)
    PINM(pins,mode,xval,yval)
    

    These are shorthand for the full names.

    Pedward had some ideas about helper instructions for smart pins:
    DACSET(pins,details)
    DAC(pins,value)
    
    PWMSET(pins,details)
    PWM(pins,value)
    

    More thought needs to go into the helpers, if they are to exist.
  • I pulled method indexing out of the interpreter and compiler. I had been thinking about Eric's, Roy's, and David's dislike for them, since they do inhibit dead code removal in compilers. I came to agree that they were likely going to cause more problems than benefits. They are gone now!

    No more of these options:

    object[index].method[index]
    object.method[index]
    method[index]

    We still have these, which are most practical:

    object[index].method
    object.method
    method
  • ersmithersmith Posts: 4,429
    edited 2020-01-16 - 12:20:47
    Sounds like things are really coming together, Chip!

    I'm still a bit skeptical of the need for DAC and PWM built-ins; if we had DAC and PWM objects then we could still have methods like:
      DAC.SET(pins, details...)
      PWM.SET(pins, details...)
    
    and the code for the object would be visible to the programmer, enabling them to learn from it, instead of being hidden inside the compiler.

    Now that you have PINMODE are you still planning to provide seperate WRPIN, WXPIN, and WYPIN instructions in Spin2?
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 12:48:29
    Eric, yes, WRPIN, WXPIN, WYPIN, etc. are still needed for flexibility. PINMODE just consolidates 5 steps that have to happen to set up most modes. Some modes don't require the WXPIN and/or WYPIN, but if they get written with 0's during initialization, it's fine.

    You can see we'll need some labels for common modes:
    con dacpin = 56
    
    pub go() | t, y
      pinm(dacpin, %10100_00000000_01_00011_0, 256, 0)	'set 16-bit DAC mode
      repeat
          _,y := polxy($7FFF, t++ << 24)			'get rotating sine
          wypin(dacpin, y ^ $8000)				'output to DAC
    
  • cgracey wrote: »
    Eric, yes, WRPIN, WXPIN, WYPIN, etc. are still needed for flexibility. PINMODE just consolidates 5 steps that have to happen to set up most modes. Some modes don't require the WXPIN and/or WYPIN, but if they get written with 0's during initialization, it's fine.
    Sounds good.
    You can see we'll need some labels for common modes:
    con dacpin = 56
    
    pub go() | t, y
      pinm(dacpin, %10100_00000000_01_00011_0, 256, 0)	'set 16-bit DAC mode
      repeat
          _,y := polxy($7FFF, t++ << 24)			'get rotating sine
          wypin(dacpin, y ^ $8000)				'output to DAC
    

    Again, couldn't the definitions be placed in objects? Does Spin2 still support notation like "dac#mode16" for getting the constant "mode16" from object "dac"?
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 13:06:32
    Yes, than object#constant is still there.

    I'm pondering requiring parentheses for all methods, since it would let us sensibly use a period, instead of the #, for object constants. Just seems cleaner:

    object.method()
    object.constant

    Variable methods must have parentheses, anyway. If we enforce them everywhere, then you'll always know when your looking at a method. Not sure what to do, yet.
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 13:10:15
    There is some pressure to dumb things down for education, making them foolproof. I think the fun thing about the P2 is that you can see an understandable bridge from Spin2 to assembly language, which enables you to learn a lot more about how things really work. To get really amazing things happening, the programmer is going to need to be able to use PASM, or rely on objects which use PASM code.
  • cgracey wrote: »
    Yes, than object#constant is still there.

    I'm pondering requiring parentheses for all methods, since it would let us sensibly use a period, instead of the #, for object constants. Just seems cleaner:

    object.method()
    object.constant

    Variable methods must have parentheses, anyway. If we enforce them everywhere, then you'll always know when your looking at a method. Not sure what to do, yet.

    I think that does look cleaner. I actually supported that notation in fastspin as an extension to Spin1 (it recognizes "object#constant" and "object.constant" interchangably). I'm not sure how your compiler works internally, but I have "kinds" associated with all symbols in an object so I can tell if a symbol is a constant, method, variable, or label. So fastspin don't actually need any special markers to distinguish constants and methods, although perhaps they would be helpful for readers. I don't have any strong feeling either way about what syntax Spin2 should use.
  • cgracey wrote: »
    Yes, than object#constant is still there.

    I'm pondering requiring parentheses for all methods, since it would let us sensibly use a period, instead of the #, for object constants. Just seems cleaner:

    object.method()
    object.constant

    Variable methods must have parentheses, anyway. If we enforce them everywhere, then you'll always know when your looking at a method. Not sure what to do, yet.

    If you are looking for votes, I'd like to cast mine for that syntax. IMHO, *all* methods need parentheses for exactly the reasons you have cited.

  • Eric, yes, I track 'types' in my compiler, which are like your 'kinds'. The use of # or a period is trivial. I will switch to a period.

    I would also like to make some switches for use within CON blocks to gate which constants become public.

    I think I will make () mandatory for all methods.
  • I'm not convinced that pinw, pinr is better than the ones spelled out: PinWrite, PinRead. TLAs and acronyms are a burden in learning. Yes it's slightly more typing. Think outside the ASM mnemonic box.
  • whicker wrote: »
    I'm not convinced that pinw, pinr is better than the ones spelled out: PinWrite, PinRead. TLAs and acronyms are a burden in learning. Yes it's slightly more typing. Think outside the ASM mnemonic box.

    Chip, I'm with @whicker too. Typing is fast, remember abreviations think not.
  • JonnyMacJonnyMac Posts: 7,008
    edited 2020-01-16 - 15:47:43
    I pulled method indexing out of the interpreter and compiler. I had been thinking about Eric's, Roy's, and David's dislike for them, since they do inhibit dead code removal in compilers.
    Is the new compiler going to do dead code removal? That would be great. I've had a couple commercial P1 projects where I would edit in Propeller Tool, but be forced to compile to binary with BST to reduce size enough to fit into the EEPROM.
    I'm pondering requiring parentheses for all methods, since it would let us sensibly use a period, instead of the #, for object constants. Just seems cleaner:

    object.method()
    object.constant
    I agree with this. In big programs I force myself to use camelCase for variables so that I can distinguish between variables and methods, but I don't like it -- other than CONSTANTS, I want to use lower case. I support using () on methods that don't require arguments.
  • whicker wrote: »
    I'm not convinced that pinw, pinr is better than the ones spelled out: PinWrite, PinRead. TLAs and acronyms are a burden in learning. Yes it's slightly more typing. Think outside the ASM mnemonic box.

    You can use either. These are the same thing, for example:

    PINTOGGLE(pins)
    PINT(pins)
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 15:55:53
    JonnyMac wrote: »
    I pulled method indexing out of the interpreter and compiler. I had been thinking about Eric's, Roy's, and David's dislike for them, since they do inhibit dead code removal in compilers.
    Is the new compiler going to do dead code removal? That would be great. I've had a couple commercial P1 projects where I would edit in Propeller Tool, but be forced to compile to binary with BST to reduce size enough to fit into the EEPROM.
    I'm pondering requiring parentheses for all methods, since it would let us sensibly use a period, instead of the #, for object constants. Just seems cleaner:

    object.method()
    object.constant
    I agree with this. In big programs I force myself to use camelCase for variables so that I can distinguish between variables and methods, but I don't like it -- other than CONSTANTS, I want to use lower case. I support using () on methods that don't require arguments.

    Dead code removal would take some work. I'd have to scoreboard which methods get called and have that data carry through the object distiller, which eliminates redundant objects. I think, in time, I'll get there.

    What I'd like to work on before too long is equation solving, so that if an equation can be solved at compile-time, it just generates a constant. Eric's compiler does this.
  • Dead code removal would take some work. I'd have to scoreboard which methods get called and have that data carry through the object distiller, which eliminates redundant objects. I think, in time, I'll get there.
    Good, thanks. I'm sure it will be less a problem for the P2, but for the P1 it has been an issue for a few of my commercial apps.

    This is all getting very exciting.
  • cgraceycgracey Posts: 13,079
    edited 2020-01-16 - 16:25:38
    JonnyMac wrote: »
    Dead code removal would take some work. I'd have to scoreboard which methods get called and have that data carry through the object distiller, which eliminates redundant objects. I think, in time, I'll get there.
    Good, thanks. I'm sure it will be less a problem for the P2, but for the P1 it has been an issue for a few of my commercial apps.

    This is all getting very exciting.

    I thought more about it since that last post.

    If I can just use one upper bit in each method index long, I can track whether that method has been referenced. The object distiller, upon finding matching objects, would OR those bits together. At the top level, you'd have awareness of every method in every object, whether they've been called from within any of the compiled instances, or not. Then, as a final step that would only be done at the top level, you would strip all methods out of all objects, stack the objects sans methods together, then add back in only the methods which had been referenced, and update all the long index pointers to point to them properly. At that time, you could also check for any redundant methods that might have existed in different objects, and eliminate those, too.
Sign In or Register to comment.