I made the changes based on Dave's explaination of the ldwa instruction. It works as expected and the DBASE value is getting passed as PAR. This is good.
However, I'm thinking that using __hub_end to drive DBASE in this case may not be correct. I think this is an issue because while the SPIN stack grows upward, the C stack grows downward.
So it seems the DBASE should be __hub_end + the desired stack size, or some parameter indicating the highest hub address to be used by the stack.
It seems to me that VBASE, DBASE and DCURR should just point to the the area of memory just after the end of the C program. In a normal Spin program, VBASE is equal to the size of the file. If there are no VAR variables then DBASE is VBASE+8 to account for the 8-byte stack frame. DCURR is then DBASE + 4*N, where N is the number of local stack variables. In our case, we don't use any local stack variables, and we don't even need the RESULT variable or a stack frame, so we could set VBASE = DBASE = DCURR = filesize.
We could put a pointer to __hub_end somewhere else, such as absolute locaton $10 since we don't need a method table.
I was only thinking of DBASE in the context of what I want to happen to the value passed to PAR in the COGINIT. So the current value of DBASE is OK, it is just using that as the value passed to PAR that is an issue.
I'm thinking it may be the most pragmatic to use a linker symbol to pass in the desired top of stack address to be passed in PAR.
I'm going to do a test to see if I can easily set it up so that if the symbol is provided the value will be used, otherwise 0x8000 will be used.
I was only thinking of DBASE in the context of what I want to happen to the value passed to PAR in the COGINIT. So the current value of DBASE is OK, it is just using that as the value passed to PAR that is an issue.
I'm thinking it may be the most pragmatic to use a linker symbol to pass in the desired top of stack address to be passed in PAR.
I'm going to do a test to see if I can easily set it up so that if the symbol is provided the value will be used, otherwise 0x8000 will be used.
C.W.
Okay, this is probably a dumb question but does the Spin stack grow up in memory or down?
I was confused about the value of __hub_end. It does represent the end of the C code, and it matches the file size. So the values in the Spin header look fine.
C.W., your ideas about using a linker symbol to override the stack value sounds good. I recall seeing other symbols with default values that can be overridden by the linker.
I was confused about the value of __hub_end. It does represent the end of the C code, and it matches the file size. So the values in the Spin header look fine.
C.W., your ideas about using a linker symbol to override the stack value sounds good. I recall seeing other symbols with default values that can be overridden by the linker.
I was hoping I could test for a linker symbol using .ifdef, but it looks like linker symbols aren't testable that way.
I was trying something like this, but it always used the 0x8000 value for the stack even when I added -Xlinker --defsym -Xlinker __stack_end=0x7f00 to the command line.
It looks to me like we would need to define a symbol, say __stack_end, set to 0x8000 in all the loader scripts, and then override it with the command line when a different value is needed, that way no testing would be required.
Does anyone know if the .ifdef .else .endif construct works for the PropGCC version of GAS?I'm not getting any exceptions, but I'm also not having much luck getting the end results I'm looking for.Thanks,C.W.
Here is a GAS pdf that may help. The Propeller section 9.30 is incomplete though.
Dave would you be able to help fill in the TODOs there ?
Bill knows this stuff but he's vacationing again.
gas can't test linker symbols in a .ifdef (the linker and gas are separate programs).
I think you can use a weak symbol definition for __stack_end; something like:
.weak __stack_end
__stack_end = 0x8000
That way __stack_end can be redefined on the command line (or in a library), but if no definition is provided elsewhere the definition in the file is used.
C.W., you should use the opcode 0x3A instead of 0x39. 0x39 just loads the next byte. 0x3A will load a word from the next two bytes. The Spin boot code will look like this:
.byte 0x3F ' Register op $1E9 Read - cogid
.byte 0x89
.byte 0xc7 ' memory op: push PBASE + next byte
.byte 0x10
.byte 0x3A ' load PAR with Stack address
.word __stack_end
.byte 0x2C ' CogInit(Id, Addr, Ptr)
Spin doesn't require the 2 bytes after 0x3A to be word aligned, but the GAS does, so you will need to start the spin boot code at address 0x17 instead of 0x18. This is OK since we don't need the method table. Change PCURR in the header from 0x0018 to 0x0017, and change the .word at 0x16 to .byte.
C.W., you should use the opcode 0x3A instead of 0x39. 0x39 just loads the next byte. 0x3A will load a word from the next two bytes. The Spin boot code will look like this:
.byte 0x3F ' Register op $1E9 Read - cogid
.byte 0x89
.byte 0xc7 ' memory op: push PBASE + next byte
.byte 0x10
.byte 0x3A ' load PAR with Stack address
.word __stack_end
.byte 0x2C ' CogInit(Id, Addr, Ptr)
Spin doesn't require the 2 bytes after 0x3A to be word aligned, but the GAS does, so you will need to start the spin boot code at address 0x17 instead of 0x18. This is OK since we don't need the method table. Change PCURR in the header from 0x0018 to 0x0017, and change the .word at 0x16 to .byte.
I think 0x39 is actually the correct opcode, your spasm document shows 0x3A as reading the next 3 bytes.
One thing I have noticed is the order seems to be an issue. If I set __stack_end to 0x8000, the LMM app fails, if I set it to 0x0080 it runs and reports the proper value in PAR.
Just for grins I tried:
.byte 0x39
.byte 0x00
.byte 0x80
This runs and reports the proper stack end value.
I appreciate everyones help and patience.
C.W.
UPDATE: I've made a work around, but until I solve the next issue of being able to externally change the value of __stack_end there isn't much point in showing it, unless someone thinks it would be helpful.
gas can't test linker symbols in a .ifdef (the linker and gas are separate programs).
I think you can use a weak symbol definition for __stack_end; something like:
.weak __stack_end
__stack_end = 0x8000
That way __stack_end can be redefined on the command line (or in a library), but if no definition is provided elsewhere the definition in the file is used.
Eric
Thanks Eric.
I've got it declared this way now in spinboot.s and whatever value I set it to directly is being properly used, but I have not had any success overriding it from the command line.
I've tried:
-D__stack_end=0x7F00 as part of the command line
and
DEFINE __stack_end 0x7F00 in my C source file
I tried removing one and both of the leading underscores as well, just for fun...
I couldn't get that syntax to work, I did get this one to work:
-Xlinker --defsym -Xlinker __stack_end=0x6F00
I've found that I can pass in the stack end value this way, but I always have to pass it.
Putting
.weak __stack_end
__stack_end=0x8000
in spinboot.s prevents it from being overridden, but without it, there is no default value.
So I think that
.weak __stack_end
__stack_end=0x8000
needs to be placed in a different file than spinboot.s.
The saga continues...
Thanks,
C.W.
Ah yes, I forgot that -Wl, won't work with options that have spaces in them like this one. Glad you found something that worked for defining symbols. Let us know if it works to move that weak definition to another file.
''
'' code to set up the Propeller chip to run C
''
'' the checksum byte should be chosen so that the sum
'' of all the bytes in the file is 0x14 ; this actually
'' means all the bytes in RAM add to 0, since the
'' loader automatically puts the bytes
'' 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF
'' on the stack at startup (this is a spin jump to 0xFFF9,
'' which in the ROM has a stop routine)
''
.section .boot, "ax", @progbits
.global __clkfreq
.global __clkmode
.extern __hub_end
.extern __stack_end 'ADDED
start
__clkfreq
.long __clkfreqval ' clock frequency
__clkmode
.byte __clkmodeval ' clock mode
chksum .byte 0x00 ' checksum: see above
.word 0x0010 ' PBASE
.global __sys_mbox ' added 20/09/11 for debugger/system support (WH)
__sys_mbox
' .word 0x7fe8 ' VBASE - start of variables
.word __hub_end ' VBASE - start of variables
' .word 0x7ff0 ' DBASE - start of stack
.word __hub_end+8 ' DBASE - start of stack
.word 0x0018 ' PCURR - initial program counter
' .word 0x7ff8 ' DCURR - initial stack pointer
.word __hub_end+12 ' DCURR - initial stack pointer
pbase
'' 8 byte header
.word 0x0008 ' length of object ?
.byte 0x02 ' number of methods ?
.byte 0x00 ' number of objects ?
.word 0x0008 ' pcurr - 0x10?
.word __stack_end ' CHANGED, a few of you said this spot wasn't being used, so I used it to store __stack_end
'' here is the spin code to switch to pasm mode
'' removed a load of the constant 0 and replaced it with cogid
.byte 0x3F ' Register op $1E9 Read - cogid
.byte 0x89
.byte 0xc7 ' memory op: push PBASE + next byte
.byte 0x10
.byte 0xA4 ' CHANGED, push the word at OBJ offset
.byte 6 ' CHANGED, offset = 6, the __stack_end value
.byte 0x2C ' CogInit(Id, Addr, Ptr)
.byte 0x32 ' Return (unused)
'' here is where the pasm code actually goes
I used the storage spot for __stack_end because when I tried a direct push using the 0x39 opcode the byte order was being reversed.
This has worked in my tests so far.
If I don't override __stack_end it uses the 0x8000 default value, otherwise it uses the value of the override.
I've been thinking that crt0_lmm.s probably isn't the most appropriate place to define the default __stack_end, because if anyone ever wanted to make a change to crt0_lmm that actually used the value it would never any override value.
Do any of you guys know of a file that is always loaded, that might be more appropriate?
C.W., You were right about the 0x39 opcode. I was using a C version of my Spasm assembler to assemble snippets of code, and it was generating the wrong bytecode. I tried it on the Spin version of the Spasm assembler that runs under Spinix, and it produced the correct bytecode. The problem with using the LDWI instruction is that the value that follows is in big-endian order. Of course, ".word __stack_end" will be stored in little-endian order. Your solution that uses LDWO (bytecode $A4) is a better solution.
''
'' code to set up the Propeller chip to run C
''
'' the checksum byte should be chosen so that the sum
'' of all the bytes in the file is 0x14 ; this actually
'' means all the bytes in RAM add to 0, since the
'' loader automatically puts the bytes
'' 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xF9, 0xFF
'' on the stack at startup (this is a spin jump to 0xFFF9,
'' which in the ROM has a stop routine)
''
.section .boot, "ax", @progbits
.global __clkfreq
.global __clkmode
.extern __hub_end
.extern __stack_end 'ADDED
start
__clkfreq
.long __clkfreqval ' clock frequency
__clkmode
.byte __clkmodeval ' clock mode
chksum .byte 0x00 ' checksum: see above
.word 0x0010 ' PBASE
.global __sys_mbox ' added 20/09/11 for debugger/system support (WH)
__sys_mbox
' .word 0x7fe8 ' VBASE - start of variables
.word __hub_end ' VBASE - start of variables
' .word 0x7ff0 ' DBASE - start of stack
.word __hub_end+8 ' DBASE - start of stack
.word 0x0018 ' PCURR - initial program counter
' .word 0x7ff8 ' DCURR - initial stack pointer
.word __hub_end+12 ' DCURR - initial stack pointer
pbase
'' 8 byte header
.word 0x0008 ' length of object ?
.byte 0x02 ' number of methods ?
.byte 0x00 ' number of objects ?
.word 0x0008 ' pcurr - 0x10?
.word __stack_end ' CHANGED, a few of you said this spot wasn't being used, so I used it to store __stack_end
'' here is the spin code to switch to pasm mode
'' removed a load of the constant 0 and replaced it with cogid
.byte 0x3F ' Register op $1E9 Read - cogid
.byte 0x89
.byte 0xc7 ' memory op: push PBASE + next byte
.byte 0x10
.byte 0xA4 ' CHANGED, push the word at OBJ offset
.byte 6 ' CHANGED, offset = 6, the __stack_end value
.byte 0x2C ' CogInit(Id, Addr, Ptr)
.byte 0x32 ' Return (unused)
'' here is where the pasm code actually goes
I used the storage spot for __stack_end because when I tried a direct push using the 0x39 opcode the byte order was being reversed.
This has worked in my tests so far.
If I don't override __stack_end it uses the 0x8000 default value, otherwise it uses the value of the override.
I made your proposed changes to spinboot.s and it seems to work. The only thing I changed was to put the weak definition of __stack_end in the default linker script rather than in crt0_lmm.s. I got the following results to my test. I'll make this an official change to propgcc once I get permission to check in another set of changes I've been working on to improve malloc heap handling in xmm mode. Oh, and I'll also have to do something similar for xmm and xmmc modes.
Thanks for your work on this and to everyone else who contributed!
David
Test program:
#include <stdio.h>
int main(void)
{
int foo;
printf("foo %08x\n", (int)&foo);
return 0;
}
Results without overriding __stack_end:
david-betzs-macbook-pro:malloc_test dbetz$ propeller-elf-gcc -Os -o stack.elf stack.c
david-betzs-macbook-pro:malloc_test dbetz$ propeller-load stack.elf -r -t
Propeller Version 1 on /dev/cu.usbserial-A8004ILf
Loading stack.elf to hub memory
13564 bytes sent
Verifying RAM ... OK
[ Entering terminal mode. Type ESC or Control-C to exit. ]
foo 00007ff8
Results overriding __stack_end on the command line:
david-betzs-macbook-pro:malloc_test dbetz$ propeller-elf-gcc -Os -Wl,--defsym,__stack_end=0x7000 -o stack.elf stack.c
david-betzs-macbook-pro:malloc_test dbetz$ propeller-load stack.elf -r -t
Propeller Version 1 on /dev/cu.usbserial-A8004ILf
Loading stack.elf to hub memory
13564 bytes sent
Verifying RAM ... OK
[ Entering terminal mode. Type ESC or Control-C to exit. ]
foo 00006ff8
Comments
I made the changes based on Dave's explaination of the ldwa instruction. It works as expected and the DBASE value is getting passed as PAR. This is good.
However, I'm thinking that using __hub_end to drive DBASE in this case may not be correct. I think this is an issue because while the SPIN stack grows upward, the C stack grows downward.
So it seems the DBASE should be __hub_end + the desired stack size, or some parameter indicating the highest hub address to be used by the stack.
C.W.
We could put a pointer to __hub_end somewhere else, such as absolute locaton $10 since we don't need a method table.
I'm thinking it may be the most pragmatic to use a linker symbol to pass in the desired top of stack address to be passed in PAR.
I'm going to do a test to see if I can easily set it up so that if the symbol is provided the value will be used, otherwise 0x8000 will be used.
C.W.
It starts at the end of the VAR section and grows up. That is, the stack index increases for push and decreases for pop.
AFAIK Spin grows up, while the LMM C programs grow down.
That is why __hub_end = ADDR(.hub) + SIZEOF(.hub) which keeps any use of the Spin stack during load from clobbering the tail end of the LMM code.
While the stack used by LMM must grow down, otherwise we couldn't normally put it at the top of the HUB.
C.W.
I'm not getting any exceptions, but I'm also not having much luck getting the end results I'm looking for.
Thanks,
C.W.
C.W., your ideas about using a linker symbol to override the stack value sounds good. I recall seeing other symbols with default values that can be overridden by the linker.
I was hoping I could test for a linker symbol using .ifdef, but it looks like linker symbols aren't testable that way.
I was trying something like this, but it always used the 0x8000 value for the stack even when I added -Xlinker --defsym -Xlinker __stack_end=0x7f00 to the command line.
It looks to me like we would need to define a symbol, say __stack_end, set to 0x8000 in all the loader scripts, and then override it with the command line when a different value is needed, that way no testing would be required.
C.W.
Here is a GAS pdf that may help. The Propeller section 9.30 is incomplete though.
Dave would you be able to help fill in the TODOs there ?
Bill knows this stuff but he's vacationing again.
Thanks,
--Steve
I think you can use a weak symbol definition for __stack_end; something like: That way __stack_end can be redefined on the command line (or in a library), but if no definition is provided elsewhere the definition in the file is used.
Eric
I think 0x39 is actually the correct opcode, your spasm document shows 0x3A as reading the next 3 bytes.
One thing I have noticed is the order seems to be an issue. If I set __stack_end to 0x8000, the LMM app fails, if I set it to 0x0080 it runs and reports the proper value in PAR.
Just for grins I tried:
.byte 0x39
.byte 0x00
.byte 0x80
This runs and reports the proper stack end value.
I appreciate everyones help and patience.
C.W.
UPDATE: I've made a work around, but until I solve the next issue of being able to externally change the value of __stack_end there isn't much point in showing it, unless someone thinks it would be helpful.
Thanks Eric.
I've got it declared this way now in spinboot.s and whatever value I set it to directly is being properly used, but I have not had any success overriding it from the command line.
I've tried:
-D__stack_end=0x7F00 as part of the command line
and
DEFINE __stack_end 0x7F00 in my C source file
I tried removing one and both of the leading underscores as well, just for fun...
C.W.
--defsym SYMBOL=EXPRESSION Define a symbol
However, because you're probably invoking the linker indirectly from propeller-elf-gcc, you'll need to use this syntax:
-Wl,--defsym SYMBOL=EXPRESSION Define a symbol
The -Wl, prefix says to pass the option on to the linker.
I couldn't get that syntax to work, I did get this one to work:
-Xlinker --defsym -Xlinker __stack_end=0x6F00
I've found that I can pass in the stack end value this way, but I always have to pass it.
Putting
.weak __stack_end
__stack_end=0x8000
in spinboot.s prevents it from being overridden, but without it, there is no default value.
So I think that
.weak __stack_end
__stack_end=0x8000
needs to be placed in a different file than spinboot.s.
The saga continues...
Thanks,
C.W.
What I have:
In crt0_lmm.s I added the __stack_end default right after the line .global __LMM_entry:
I made the changes noted below to spinboot.s
Comments are ADDED and CHANGED
I used the storage spot for __stack_end because when I tried a direct push using the 0x39 opcode the byte order was being reversed.
This has worked in my tests so far.
If I don't override __stack_end it uses the 0x8000 default value, otherwise it uses the value of the override.
I use the following to override:
-Xlinker --defsym -Xlinker __stack_end=0x7F00
I'm entering it as a Compile Option in SimpleIDE.
Thanks for all the help.
Chris Wardell
Edit: Here is my update source:
stack_end.zip
Do any of you guys know of a file that is always loaded, that might be more appropriate?
Thanks,
C.W.
Hi Chris,
I made your proposed changes to spinboot.s and it seems to work. The only thing I changed was to put the weak definition of __stack_end in the default linker script rather than in crt0_lmm.s. I got the following results to my test. I'll make this an official change to propgcc once I get permission to check in another set of changes I've been working on to improve malloc heap handling in xmm mode. Oh, and I'll also have to do something similar for xmm and xmmc modes.
Thanks for your work on this and to everyone else who contributed!
David
Test program:
Results without overriding __stack_end:
Results overriding __stack_end on the command line:
Thanks again to everyone for there help and patience.
Chris Wardell
C.W. The latest SimpleIDE v0-6-10 package includes the propeller-gcc toolchain that supports __stack_end.
Thanks for your effort!
--Steve
Thanks Steve, I just tried it out and it is working well.
Hopefully I can use SimpleIDE and PropGCC to build some success stories.
C.W.