PropBasic: Launch program in ram

Hello!
Have been experimenting with a self-executing program, but am failing to understand the launch code (chip's code).
There is a valid eeprom image stored in the upper part of a 64kB eeprom at pins 28/29 ($8000 - $FFFF)
I tested the image by launching it with a spin loader from the obex.
The plan is to launch this eeprom image using PropBasic, or inline pasm.
I added the following code at the end of the PropBasic file:
My code file copies the image from eeprom to ram, then does a "GOTO launch" to run the above code. I tested the image in ram after copying it... It can read it back and write it to PST, and all the bytes seem to match the original code.eeprom file.
-- I suspect the problem is with the copy/pasted launch code. Regrettably I do not really understand it all!!. So my question would be...:
Q: Should this snippet of inline ASM code actually work, or is something seriously wrong with this approach ?
Ultimately I would like to be able to call a simple PropBasic command to restart the propeller running whatever code is in ram. Ie. (A kind of soft reboot!)
(A few months ago Bean told that this might be tough to implement... Some months on I am not ready to admit defeat, but I am feeling he was right!)
Have been experimenting with a self-executing program, but am failing to understand the launch code (chip's code).
There is a valid eeprom image stored in the upper part of a 64kB eeprom at pins 28/29 ($8000 - $FFFF)
I tested the image by launching it with a spin loader from the obex.
The plan is to launch this eeprom image using PropBasic, or inline pasm.
I added the following code at the end of the PropBasic file:
tmpAddr long
smode CON 0
time_xtal CON 100000 ' 20 * 20000 / 4 / 1 '20ms (@20MHz, 1 inst/loop)
interpreter CON $43C010 ' $0001 << 18 + $3C01 << 4 + %0000
ASM
'
' Launch program in ram
'
launch mov tmpAddr,#0 'set tmpAddr to zero
rdword tmpAddr,#$0004+2 'if pbase address invalid, shutdown
cmp tmpAddr,#$0010 wz
if_nz jmp #shutdown
rdbyte tmpAddr,#$0004 'if xtal/pll enabled, start up now
and tmpAddr,#$F8 '..while remaining in rcfast mode
clkset tmpAddr
:delay djnz time_xtal,#:delay 'allow 20ms @20MHz for xtal/pll to settle
rdbyte tmpAddr,#$0004 'switch to selected clock
clkset tmpAddr
coginit interpreter 'reboot cog with interpreter
'
'
' Shutdown
'
shutdown nop ' mov ee_jmp,#0 'deselect eeprom (replace jmp with nop)
:call nop ' call #ee_stop '(always returns)
' cmp smode,#0 wz 'if serial mode, send error (z=0)
'if_nz mov smode,#0 '(only do once)
'if_nz mov :call,#0 '(replace call with nop)
'if_nz call #tx_bit_align '(may return to shutdown, no problem)
mov dira,#0 'cancel any outputs
mov smode,#$02 'stop clock
clkset smode '(suspend until reset)
ENDASM
My code file copies the image from eeprom to ram, then does a "GOTO launch" to run the above code. I tested the image in ram after copying it... It can read it back and write it to PST, and all the bytes seem to match the original code.eeprom file.
-- I suspect the problem is with the copy/pasted launch code. Regrettably I do not really understand it all!!. So my question would be...:
Q: Should this snippet of inline ASM code actually work, or is something seriously wrong with this approach ?
Ultimately I would like to be able to call a simple PropBasic command to restart the propeller running whatever code is in ram. Ie. (A kind of soft reboot!)
(A few months ago Bean told that this might be tough to implement... Some months on I am not ready to admit defeat, but I am feeling he was right!)

Comments
Jeff T.
I am a little concerned about:
mov address,taskparam 'retrieve array
Not certain that it actually moves the propbasic defined long array into the asm address- and in the correct format, and not sure yet how to test that in pasm.At the moment I call the task like this from the main program (cog0):
COGINIT BootloaderTask, 0
Cog0 does seem to immediately stop as my status leds driven from the main cog program go off. But then it hangs.
Maybe I should not be launching a cog into cog0 from cog0? I tried an intermediate cog1 which simply stopped the first cog0 and launched the new cog0, but that did not seem to help.
If I run the obex bootloader (spin code), it correctly runs the image I have stored in the upper eeprom- so I believe that part is ok.
... another day of probing begins !
taskparam(1) should =0 which is the default EEPROM that comes with the Prop boards
taskparam(2) should =$8000 which is the location in memory that you want your read to begin
Jeff T.
I am using a PPDB and have changed the supplied eeprom to a 64kB version, 24FC512
So I have the params set as you noted above (pin, chipaddress, eeprommem) = (28, 0, $8000).
Thanks for your help- I am struggling to debug this! I am currently trying to craft some simple ASM to write bytes to the attached (via usb) onboard PST. I hope that would at least help me discover when the program dies by sending a byte at various points in the code and "seeing" where the code gets to.
This is what Jeff ("Hi!") referred to a few posts up:
taskparam(1) is equivalent to chip address, taskparam(2) is memory start
Sorry, I had reversed them a couple times whilst testing. I have set them back to the following, but still no joy.
mem_start long $8000 pin_num long 1 << 28 chip_address long 0
(I have updated the files attached to post 7.)
--
I did notice something which may or maynot be an issue... to do with the timings.
DEVICE P8X32A, XTAL1, PLL16X XIN 5_000_000
and
time_xtal long 20 * 20000 / 4 / 1 '20ms (@20MHz, 1 inst/loop)
I was running the code at 80MHz, not 20 MHz as is assumed by the time_xtal formula
I tried changing to PLL4X, and also adjusting the time_xtal delay to make it 20ms at 80MHz, but it did not seem to make a difference.
Not sure if the bootloader operation is timing critical...???
shl mask_scl,[COLOR="red"]pin_num[/COLOR] shl mask_sda,[COLOR="red"]pin_num[/COLOR] ... mem_start long $8000 [COLOR="red"]pin_num long 1 << 28[/COLOR]
Does that seem odd? You really need the pin number here (#28) not a mask.pin_num long 28
I just checked again the original code from unsoundcode (post #2.)
the only difference seems to be that he calls the coginit (starts the task) like this
repeat 2 waitcnt(clkfreq/100 + cnt) clkset(0,12000000) coginit(0,@Entry,array_ptr)
Could the clkset be vital here? I don't seem to be able to handle that with PropBasic, but maybe there is a PASM alternative?
http://forums.parallax.com/showthread.php?122326-CLKSET-in-ASM&p=905516&viewfull=1#post905516
clkset :mode wrlong :freq, #0 wrbyte :mode, #4 :mode long %0000_0000 :freq long 12_000_000
It does not solve the matter, but surely it proves the frequency is now set the same as the original program.
Also I changed 2 lines thus, to "ensure / hope" the pin_num setting is correct
shl mask_scl, #28 'pin_num shl mask_sda, #28 'pin_num
I have added some extra led flashes through the code. The codes executes until this block, but hangs at [ call #ee_read ] - so an led before this line flashes, but not after. It might be a PIN issue yet... Is it possible somewhere between PropBasic and PASM, the PIN is not being defined or init'd correctly? How would I do that in PASM?
boot mov smode,#0 'clear mode in case error call #ee_read 'send read command :loop call #ee_receive 'get eeprom byte wrbyte eedata,address 'write to ram add address,#1 cmp count,first_byte wz 'calculate the file length if_z mov low_byte,eedata 'from the word value in cmp count,second_byte wz 'bytes at address $0008 and $0009 if_z call #getcount djnz count,#:loop 'loop until done call #ee_stop 'end read (followed by launch)
I have found the problematic code here
ee_start mov bits,#9 '1 ready 9 start attempts :loop andn outa,mask_scl '1(!) ready scl low or dira,mask_scl '1! scl low nop '1 andn dira,mask_sda '1! sda float call #delay3 '5 or outa,mask_scl '1! scl high nop '1 test mask_sda,ina wc 'h?h sample sda if_nc djnz bits,#:loop '1,2 if sda not high, loop until done if_nc jmp #shutdown '1 if sda still not high, shutdown or dira,mask_sda '1! sda low
It would seem the code loops until it gives-up and does the jmp #shutdown.
The RCFAST settings seem to make no difference either.
I have attached revised version of the code to reflect all the adjustments.
I have attempted to implement the same parameter loading as Jeff used, and set the clk to RCFAST, so in theory everything "should" be exactly the same (except for the compiler of course).
time for a little gardening / head recharging!
mask_sda long $2
mask_scl long $1
pin_num long $1C
mem_start long $8000
chip_address long 0
cs_write long $A0
cs_read long $A1
you could also try deleting the following lines from the "boot" label they are probably not needed in you app
cmp count,first_byte wz 'calculate the file length
if_z mov low_byte,eedata 'from the word value in
cmp count,second_byte wz 'bytes at address $0008 and $0009
if_z call #getcount
Jeff T.
When PropBasic creates the spin file, it starts with something like this:
PUB Init(pv_DataStart) Return ((pv_DataStart >> 2) << 18) + ((@__INIT >> 2) << 4)
By manually inserting a clkset, the problem was solved.
PUB Init(pv_DataStart) clkset(0,12000000) Return ((pv_DataStart >> 2) << 18) + ((@__INIT >> 2) << 4)
Maybe an advanced option of the PropBasic COGINIT command might allow a parameter for setting the clkspeed of the new cog.
Or maybe I can work around this somehow... I already tried changing the clk when the new task starts without success., but maybe I just need to twiddle with some delays...
Will report back!
So here is a work around.... No need for the manual clkset edit of the spin file
Just ensure this appears at the start of the task. I found that not only should we set the clock speed, but also zero the pin registers. I believe it might be an issue with the PropBasic compiler which could be easily solved, so I will post an explanation on the PropBasic thread.
mov dira,#0 mov outa,#0 clkset clkmode12 wrlong clkfreq12, #0 wrbyte clkmode12, #4
Again, BIG BIG thanks for your persistence - it feels really good to crack this nut !
Max.
Jeff T.