Maybe I'm very confused on how libraries work. I was under the impression that I could take a single function (or a bunch of functions) and put it in a library file (libPropWare.a). I could then write a program (SPI_Demo.c) which called a function within libPropWare.a and create an executable SPI_Demo.elf. I could also write a hundred other programs that called the same function(s) within libPropWare.a and I'd never have to re-compile libPropWare.a. ...
You're not confused.
This happens with SimpleIDE libraries.
Sorry, but my time is very limited today so I can't help more than I have already.
Perhaps David will help since he created common.mk.
The _load_start_xxx symbols are defined by the linker when building an executable. They will never appear in a library. That also means that pulling COG code out of a library can be tricky sometimes, because library files are only included when a symbol in them is referred to, and _load_start_xxx is not a symbol in any library file.
The way around this is to refer to *some* symbol in the .o file you want linked. For example, you could place an initialization function that loads the COG in there. Or you could declare a mailbox variable that your main C code uses. Anything at all -- but it has to be an explicit symbol, not something like _load_start_xxx.
The _load_start_xxx symbols are defined by the linker when building an executable. They will never appear in a library. That also means that pulling COG code out of a library can be tricky sometimes, because library files are only included when a symbol in them is referred to, and _load_start_xxx is not a symbol in any library file.
The way around this is to refer to *some* symbol in the .o file you want linked. For example, you could place an initialization function that loads the COG in there. Or you could declare a mailbox variable that your main C code uses. Anything at all -- but it has to be an explicit symbol, not something like _load_start_xxx.
Hope this helps.
I figured out a way around this for the drivers that are in the library. Now I just have to remember what I did! :-(
The _load_start_xxx symbols are defined by the linker when building an executable. They will never appear in a library. That also means that pulling COG code out of a library can be tricky sometimes, because library files are only included when a symbol in them is referred to, and _load_start_xxx is not a symbol in any library file.
The way around this is to refer to *some* symbol in the .o file you want linked. For example, you could place an initialization function that loads the COG in there. Or you could declare a mailbox variable that your main C code uses. Anything at all -- but it has to be an explicit symbol, not something like _load_start_xxx.
Hope this helps.
If I understood that correctly (which I'm not 100% sure I did), I'm already doing that. libPropWare.a contains spi.c and spi_as.S. Those two files contain driver code for SPI comms, including the cog initialization (line 86 of spi.c). My demo application contains SPI_Demo.c and, within this file, I call SPIStart() from spi.c. I believe that call is what you're suggesting - something from outside the library calls an explicit label (that label is _SPIStart in this case) and then an internal function relative to the library file can start the cog.
I've removed the extra demo files and cleaned the Debug folder, so there are slightly fewer files in it now.
Creation of the library can be done from within the Debug folder with "make -f../Makefile" (you'll need to set the PROPGCC_PREFIX variable in Makefile) and then the same command can be run from PropGCC_Demos/SPI/Debug with the same addition to PropGCC_Demos/SPI/Makefile. I did it this way so that it plays nicely with Eclipse and requires minimal changes to the default settings for any Eclipse CDT build.
If I understood that correctly (which I'm not 100% sure I did), I'm already doing that. libPropWare.a contains spi.c and spi_as.S. Those two files contain driver code for SPI comms, including the cog initialization (line 86 of spi.c). My demo application contains SPI_Demo.c and, within this file, I call SPIStart() from spi.c.
Right, you have a reference to a function in spi.o, but you don't have any reference to spi_as.o (the file produced from spi_as.S) and so that file is *not* being pulled out of the library into your project. That's the difference between putting things into a library (.a file) and linking them all explicitly on the command line. The linker only takes the files from the library that are actually being used (that have references to them). Each .o file in the library is treated seperately for this purpose.
The problem you're encountering is that you want spi_as.o to be linked, but the only reference to it is the implicit label _load_start_spi_as. That label doesn't actually exist anywhere in the object files, it is created by the linker when the spi_as_cog section is encountered. That leads to a chicken and egg problem -- the spi_as_cog section won't be included because there's no reference to anything in spi_as.o. You'll have to create some kind of dummy reference in spi_as.o to force it to be linked.
Okay, I'm understanding your point now, but unable to get it to work. There should be a label "led16" in spi_as.o (and I can see it in the map of libPropWare.a) so if I write a line in SPI_Demo.c that read "extern uint32_t led16[];", it should match to the label in spi_as.o correct?
That's not working though. I thought maybe the compiler was optimizing that line out, so I stuck a simple "int x = *led16" at the top of SPI_Demo.c's main function and it didn't help any either. Perhaps it's still optimizing it out?
Also, I've attached the map file of libPropWare.a for reference
In archive libPropWare.a:
PropWare.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 g .text 00000000 0x40 _GPIOSwitchRead_Low
00000000 *UND* 00000000 DIRA
00000000 *UND* 00000000 OUTA
00000000 *UND* 00000000 __clkfreq
00000000 *UND* 00000000 CNT
0000003e g .text 00000000 0x40 _PropWareCountBits
00000052 g .text 00000000 0x40 _PropWareGetPinNum
spi.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l .text 00000000 0x40 _SPIReadPar
00000000 l .data 00000000 0x40 _g_mailbox
00000004 l .data 00000000 0x40 _g_spiCog
00000286 l .text 00000000 0x40 .L40
000002ab l .text 00000000 0x40 .L43
000002ad l .text 00000000 0x40 .L39
00000000 *UND* 00000000 __clkfreq
00000000 *UND* 00000000 CNT
0000005e g .text 00000000 0x40 _SPIStop
00000080 g .text 00000000 0x40 _SPIIsRunning
00000094 g .text 00000000 0x40 _SPIWait
000000c4 g .text 00000000 0x40 _SPIWaitSpecific
000000f7 g .text 00000000 0x40 _SPISetMode
0000012d g .text 00000000 0x40 _SPISetBitMode
00000169 g .text 00000000 0x40 _SPISetClock
000001ae g .text 00000000 0x40 _SPIStart
00000000 *UND* 00000000 _PropWareCountBits
00000000 *UND* 00000000 __load_start_spi_as_cog
00000000 *UND* 00000000 _PropWareGetPinNum
000002b1 g .text 00000000 0x40 _SPIGetClock
000002f2 g .text 00000000 0x40 _SPIShiftOut
0000032d g .text 00000000 0x40 _SPIShiftIn
00000380 g .text 00000000 0x40 _SPIShiftOut_fast
000003a0 g .text 00000000 0x40 _SPIShiftIn_fast
000003f5 g .text 00000000 0x40 _SPIShiftIn_sector
spi_as.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d spi_as_cog 00000000 spi_as_cog
000004a4 l spi_as_cog 00000000 testLEDs
00000490 l spi_as_cog 00000000 negOne
00000440 l spi_as_cog 00000000 READ_CMD
00000450 l spi_as_cog 00000000 READ_CMD_ret
000004f0 l spi_as_cog 00000000 mosi
000004cc l spi_as_cog 00000000 mailbox
000004f4 l spi_as_cog 00000000 mosiPinNum
000004f8 l spi_as_cog 00000000 miso
000004fc l spi_as_cog 00000000 misoPinNum
00000500 l spi_as_cog 00000000 sclk
0000003c l spi_as_cog 00000000 LOOP
000004d0 l spi_as_cog 00000000 temp
00000494 l spi_as_cog 00000000 spiFuncBits
000000d0 l spi_as_cog 00000000 SEND
00000170 l spi_as_cog 00000000 READ
00000270 l spi_as_cog 00000000 SEND_fast
000002f8 l spi_as_cog 00000000 READ_fast
000003d8 l spi_as_cog 00000000 read_sector
00000094 l spi_as_cog 00000000 SET_MODE
000000ac l spi_as_cog 00000000 SET_BITMODE
000000b8 l spi_as_cog 00000000 SET_FREQ
000000c4 l spi_as_cog 00000000 GET_FREQ
00000454 l spi_as_cog 00000000 READ_DATA
00000464 l spi_as_cog 00000000 READ_DATA_ret
000004e4 l spi_as_cog 00000000 clkPhase
000004e0 l spi_as_cog 00000000 bitmode
00000504 l spi_as_cog 00000000 clkDelay
000004ec l spi_as_cog 00000000 data
00000468 l spi_as_cog 00000000 WRITE_DATA
00000478 l spi_as_cog 00000000 WRITE_DATA_ret
000004e8 l spi_as_cog 00000000 bitCount
00000498 l spi_as_cog 00000000 spiBitCountBits
000000dc l spi_as_cog 00000000 SEND_rd_data
0000049c l spi_as_cog 00000000 dataMask
000004dc l spi_as_cog 00000000 clock
00000110 l spi_as_cog 00000000 msb_first
000004d8 l spi_as_cog 00000000 loopIdx
0000013c l spi_as_cog 00000000 lsb_first
00000168 l spi_as_cog 00000000 SEND_complete
000001a4 l spi_as_cog 00000000 read_msb_first
0000023c l spi_as_cog 00000000 lsb_cpha1
0000026c l spi_as_cog 00000000 lsb_cpha1_ret
000001e0 l spi_as_cog 00000000 lsb_cpha0
00000210 l spi_as_cog 00000000 lsb_cpha0_ret
000001b0 l spi_as_cog 00000000 finish_lsb_first
00000214 l spi_as_cog 00000000 msb_cpha1
00000238 l spi_as_cog 00000000 msb_cpha1_ret
000001b8 l spi_as_cog 00000000 msb_cpha0
000001dc l spi_as_cog 00000000 msb_cpha0_ret
0000027c l spi_as_cog 00000000 SEND_rd_data_fast
000002a8 l spi_as_cog 00000000 msb_first_fast
000002cc l spi_as_cog 00000000 lsb_first_fast
000002f0 l spi_as_cog 00000000 SEND_complete_fast
0000032c l spi_as_cog 00000000 read_msb_first_fast
000003ac l spi_as_cog 00000000 lsb_post_fast
000003d4 l spi_as_cog 00000000 lsb_post_fast_ret
00000360 l spi_as_cog 00000000 lsb_pre_fast
00000388 l spi_as_cog 00000000 lsb_pre_fast_ret
00000338 l spi_as_cog 00000000 finish_lsb_first_fast
0000038c l spi_as_cog 00000000 msb_post_fast
000003a8 l spi_as_cog 00000000 msb_post_fast_ret
00000340 l spi_as_cog 00000000 msb_pre_fast
0000035c l spi_as_cog 00000000 msb_pre_fast_ret
000003d8 l spi_as_cog 00000000 read_sector_addr
000004a0 l spi_as_cog 00000000 sdSectorSize
000003e8 l spi_as_cog 00000000 beginSectorRead
000003ec l spi_as_cog 00000000 read_byte
00000418 l spi_as_cog 00000000 POST_CLOCK
00000428 l spi_as_cog 00000000 POST_CLOCK_ret
0000042c l spi_as_cog 00000000 PRE_CLOCK
0000043c l spi_as_cog 00000000 PRE_CLOCK_ret
0000046c l spi_as_cog 00000000 write_loop
0000047c l spi_as_cog 00000000 SEND_TO_LED
000004d4 l spi_as_cog 00000000 temp2
0000048c l spi_as_cog 00000000 SEND_TO_LED_ret
000004a8 l spi_as_cog 00000000 led16
000004ac l spi_as_cog 00000000 led17
000004b0 l spi_as_cog 00000000 led18
000004b4 l spi_as_cog 00000000 led19
000004b8 l spi_as_cog 00000000 led20
000004bc l spi_as_cog 00000000 led21
000004c0 l spi_as_cog 00000000 led22
000004c4 l spi_as_cog 00000000 led23
000004c8 l spi_as_cog 00000000 quarterSecond
00000000 *UND* 00000000 dira
00000000 *UND* 00000000 par
00000000 *UND* 00000000 outa
00000000 *UND* 00000000 cnt
00000000 *UND* 00000000 ina
sd.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000004 l O .bss 00000001 _g_sd_firstByteResponse
00000000 l O .bss 00000004 _g_sd_cs
00000173 l .text 00000000 0x40 .L37
00000231 l .text 00000000 0x40 .L34
00000263 l .text 00000000 0x40 .L43
000002dc l .text 00000000 0x40 .L47
000002de l .text 00000000 0x40 .L33
000003cf l .text 00000000 0x40 .L66
000003d1 l .text 00000000 0x40 .L55
00000490 l .text 00000000 0x40 .L81
00000492 l .text 00000000 0x40 .L73
0000022c l O .bss 00000001 _g_sd_fatMod
00000010 l O .bss 00000004 _g_sd_fatStart
00000224 l O .bss 00000004 _g_sd_curFatSector
00000024 l O .bss 00000200 _g_sd_fat
00000020 l O .bss 00000004 _g_sd_fatSize
000006ac l .text 00000000 0x40 .L107
000006ad l .text 00000000 0x40 .L104
00000014 l O .bss 00000004 _g_sd_rootAddr
0000000c l O .bss 00000001 _g_sd_filesystem
0000001c l O .bss 00000004 _g_sd_rootAllocUnit
00000005 l O .bss 00000001 _g_sd_sectorsPerCluster_shift
00000018 l O .bss 00000004 _g_sd_firstDataAddr
0000000e l O .bss 00000002 _g_sd_entriesPerFatSector_Shift
00000749 l .text 00000000 0x40 .L113
00000796 l .text 00000000 0x40 .L115
00000008 l O .bss 00000004 _g_sd_rootDirSectors
00000228 l O .bss 00000004 _g_sd_dir_firstAllocUnit
00000961 l .text 00000000 0x40 .L119
00000a3f l .text 00000000 0x40 .L147
00000a41 l .text 00000000 0x40 .L144
00000a71 l .text 00000000 0x40 .L142
00000ae6 l .text 00000000 0x40 .L150
00000b80 l .text 00000000 0x40 .L160
00000c71 l .text 00000000 0x40 .L176
00000ccf l .text 00000000 0x40 .L174
00000db3 l .text 00000000 0x40 .L186
00000e39 l .text 00000000 0x40 .L194
00000ed7 l .text 00000000 0x40 .L234
00000f29 l .text 00000000 0x40 .L238
00000f30 l .text 00000000 0x40 .L231
00000f50 l .text 00000000 0x40 .L233
00000f6a l .text 00000000 0x40 .L236
00000fc1 l .text 00000000 0x40 .L235
00000fc9 l .text 00000000 0x40 .L232
00000fe2 l .text 00000000 0x40 .L237
000010bc l .text 00000000 0x40 .L240
00001118 l .text 00000000 0x40 .L242
000011b5 l .text 00000000 0x40 .L247
0000128a l .text 00000000 0x40 .L276
000012f7 l .text 00000000 0x40 .L263
0000022d l O .bss 00000001 _g_sd_fileID
000014ce l .text 00000000 0x40 .L282
00000000 l .data 00000000 0x40 .LC0
00001659 l .text 00000000 0x40 .L324
00001667 l .text 00000000 0x40 .L321
00000008 l .data 00000000 0x40 .LC1
0000004c l .data 00000000 0x40 .LC2
00000058 l .data 00000000 0x40 .LC3
00000060 l .data 00000000 0x40 .LC4
00000064 l .data 00000000 0x40 .LC5
00000068 l .data 00000000 0x40 .LC6
0000006c l .data 00000000 0x40 .LC7
00000074 l .data 00000000 0x40 .LC8
0000007c l .data 00000000 0x40 .LC9
00000094 l .data 00000000 0x40 .LC10
000000b4 l .data 00000000 0x40 .LC11
000000d4 l .data 00000000 0x40 .LC12
000000f8 l .data 00000000 0x40 .LC13
000016b2 l .text 00000000 0x40 .L356
000017ad l .text 00000000 0x40 .L345
000017c2 l .text 00000000 0x40 .L354
0000182d l .text 00000000 0x40 .L330
0000183a l .text 00000000 0x40 .L349
00000000 g .text 00000000 0x40 _SDfeof
00000013 g .text 00000000 0x40 _SDfseekr
00000045 g .text 00000000 0x40 _SDfseekw
00000077 g .text 00000000 0x40 _SDftellr
0000007c g .text 00000000 0x40 _SDftellw
00000081 g .text 00000000 0x40 _SDSendCommand
00000000 *UND* 00000000 _SPIShiftOut
000000bb g .text 00000000 0x40 _SDGetResponse
00000000 *UND* 00000000 __clkfreq
00000000 *UND* 00000000 CNT
00000000 *UND* 00000000 _SPIShiftIn
00000133 g .text 00000000 0x40 _SDStart
00000000 *UND* 00000000 DIRA
00000000 *UND* 00000000 OUTA
00000000 *UND* 00000000 _SPIStart
00000000 *UND* 00000000 _SPIWait
00000000 *UND* 00000000 _SPISetClock
000002e4 g .text 00000000 0x40 _SDReadBlock
00000000 *UND* 00000000 __MASK_0000FFFF
00000000 *UND* 00000000 _SPIShiftIn_fast
000003d7 g .text 00000000 0x40 _SDWriteBlock
00000000 *UND* 00000000 _SPIShiftOut_fast
00000496 g .text 00000000 0x40 _SDReadDataBlock
000004f1 g .text 00000000 0x40 _SDWriteDataBlock
0000054c g .text 00000000 0x40 _SDUnmount
00000218 O *COM* 00000004 _g_sd_buf
000005a4 g .text 00000000 0x40 _SDReadDat16
000005b6 g .text 00000000 0x40 _SDReadDat32
000005d9 g .text 00000000 0x40 _SDWriteDat16
000005e5 g .text 00000000 0x40 _SDWriteDat32
00000601 g .text 00000000 0x40 _SDfclose
000006b1 g .text 00000000 0x40 _SDGetSectorFromPath
000006b7 g .text 00000000 0x40 _SDGetSectorFromAlloc
000006d9 g .text 00000000 0x40 _SDGetFATValue
0000079a g .text 00000000 0x40 _SDMount
00000965 g .text 00000000 0x40 _SDLoadSectorFromOffset
00000a73 g .text 00000000 0x40 _SDIncCluster
00000ae8 g .text 00000000 0x40 _SDLoadNextSector
00000b84 g .text 00000000 0x40 _SDGetFilename
00000be7 g .text 00000000 0x40 _SDFind
00000000 *UND* 00000000 _strcmp
00000cd5 g .text 00000000 0x40 _SDchdir
00000db9 g .text 00000000 0x40 _SDReloadBuf
00000e3b g .text 00000000 0x40 _SDfgetc
00000e81 g .text 00000000 0x40 _SDfgets
00000eb6 g .text 00000000 0x40 _SDFindEmptySpace
00001049 g .text 00000000 0x40 _SDExtendFAT
0000111a g .text 00000000 0x40 _SDfputc
000011b9 g .text 00000000 0x40 _SDfputs
000011d7 g .text 00000000 0x40 _SDCreateFile
000012f9 g .text 00000000 0x40 _SD_Shell_touch
00001325 g .text 00000000 0x40 _SDfopen
000014d2 g .text 00000000 0x40 _SD_Shell_cat
00000000 *UND* 00000000 ___files
00000000 *UND* 00000000 _fputc
0000150b g .text 00000000 0x40 _SDPrintFileAttributes
00001587 g .text 00000000 0x40 _SDPrintFileEntry
00000000 *UND* 00000000 _printf
000015ca g .text 00000000 0x40 _SD_Shell_ls
0000166b g .text 00000000 0x40 _SD_Shell
00000000 *UND* 00000000 _memset
00000000 *UND* 00000000 _puts
00000000 *UND* 00000000 _gets
l3g.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l .text 00000000 0x40 _L3GWrite8
0000005c l .text 00000000 0x40 _L3GRead8
000000c0 l .text 00000000 0x40 _L3GRead16
00000138 l .text 00000000 0x40 .L9
00000283 l .text 00000000 0x40 .L22
000002f1 l .text 00000000 0x40 .L27
00000000 g .bss 00000000 0x40 _g_l3g_alwaysSetMode
00000000 *UND* 00000000 _SPISetMode
00000000 *UND* 00000000 _SPISetBitMode
00000004 O *COM* 00000004 _g_l3g_cs
00000000 *UND* 00000000 OUTA
00000000 *UND* 00000000 _SPIShiftOut
00000000 *UND* 00000000 _SPIWait
00000000 *UND* 00000000 _SPIShiftIn
0000013c g .text 00000000 0x40 _L3GStart
00000000 *UND* 00000000 _SPIIsRunning
00000000 *UND* 00000000 _SPIStart
00000000 *UND* 00000000 DIRA
000001a9 g .text 00000000 0x40 _L3GAlwaysSetMode
000001af g .text 00000000 0x40 _L3GReadX
000001ba g .text 00000000 0x40 _L3GReadY
000001c5 g .text 00000000 0x40 _L3GReadZ
000001d0 g .text 00000000 0x40 _L3GRead
000001df g .text 00000000 0x40 _L3GReadAll
00000287 g .text 00000000 0x40 _L3G_ioctl
mcp300x.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
000000da l .text 00000000 0x40 .L8
00000159 l .text 00000000 0x40 .L11
00000000 g .text 00000000 0x40 _MCP300xStart
00000001 O *COM* 00000001 _g_mcp300x_cs
00000000 *UND* 00000000 DIRA
00000000 *UND* 00000000 OUTA
00000000 *UND* 00000000 _SPIIsRunning
00000000 *UND* 00000000 _SPIStart
00000000 *UND* 00000000 _SPISetMode
00000000 *UND* 00000000 _SPISetBitMode
00000059 g .text 00000000 0x40 _MCP300xAlwaysSetMode
00000000 g .bss 00000000 0x40 _g_mcp300x_alwaysSetMode
0000005f g .text 00000000 0x40 _MCP300xRead
00000000 *UND* 00000000 _SPIShiftOut
00000000 *UND* 00000000 _SPIShiftIn
000000de g .text 00000000 0x40 _MCP300xReadDif
hd44780.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l .text 00000000 0x40 _HD44780ClockPulse
00000008 l O .bss 00000004 _g_hd44780_en
0000002d l .text 00000000 0x40 _HD44780Write
00000004 l O .bss 00000004 _g_hd44780_rw
00000018 l O .bss 00000004 _g_hd44780_bitmode
00000010 l O .bss 00000001 _g_hd44780_dataLSBNum
0000000c l O .bss 00000004 _g_hd44780_dataMask
00000095 l .text 00000000 0x40 _HD44780Cmd
00000000 l O .bss 00000004 _g_hd44780_rs
00000020 l O .bss 00000001 _g_hd44780_curRow
00000021 l O .bss 00000001 _g_hd44780_curCol
00000014 l O .bss 00000004 _g_hd44780_dim
0000001c l O .bss 00000004 _g_hd44780_memMap
0000022d l .text 00000000 0x40 .L61
00000248 l .text 00000000 0x40 .L20
0000025e l .text 00000000 0x40 .L62
00000262 l .text 00000000 0x40 .L22
00000271 l .text 00000000 0x40 .L23
00000289 l .text 00000000 0x40 .L24
00000290 l .text 00000000 0x40 .L25
0000029f l .text 00000000 0x40 .L63
000002b9 l .text 00000000 0x40 .L27
000002be l .text 00000000 0x40 .L59
000002c7 l .text 00000000 0x40 .L29
000002ce l .text 00000000 0x40 .L30
000002da l .text 00000000 0x40 .L53
000002df l .text 00000000 0x40 .L56
000002e4 l .text 00000000 0x40 .L54
000003a2 l .text 00000000 0x40 .L41
000003a6 l .text 00000000 0x40 .L45
000003a8 l .text 00000000 0x40 .L9
000004a1 l .text 00000000 0x40 .L85
000004a4 l .text 00000000 0x40 .L76
00000528 l .text 00000000 0x40 .L89
000005cf l .text 00000000 0x40 .L127
00000630 l .text 00000000 0x40 .L120
0000063a l .text 00000000 0x40 .L129
0000063e l .text 00000000 0x40 .L118
00000642 l .text 00000000 0x40 .L117
00000647 l .text 00000000 0x40 .L116
00000000 *UND* 00000000 OUTA
00000000 *UND* 00000000 __clkfreq
00000000 *UND* 00000000 CNT
000000ab g .text 00000000 0x40 _HD44780Clear
000000d8 g .text 00000000 0x40 _HD44780Start
00000000 *UND* 00000000 _PropWareCountBits
00000000 *UND* 00000000 DIRA
000003aa g .text 00000000 0x40 _HD44780Move
00000418 g .text 00000000 0x40 _HD44780_putchar
000004a6 g .text 00000000 0x40 _HD44780_puts
000004b9 g .text 00000000 0x40 _HD44780_int
0000052c g .text 00000000 0x40 _HD44780_uint
0000057e g .text 00000000 0x40 _HD44780_hex
000005c4 g .text 00000000 0x40 _HD44780_printf
Okay, I'm understanding your point now, but unable to get it to work. There should be a label "led16" in spi_as.o (and I can see it in the map of libPropWare.a) so if I write a line in SPI_Demo.c that read "extern uint32_t led16[];", it should match to the label in spi_as.o correct?
No, that won't work (at least not as is). There are actually two issues:
(1) led16 is not marked as ".global", and so its definition is local to that specific .o file (like a C "static" variable). It can't be referenced from outside.
(2) There's another wrinkle: to avoid conflict with assembly language labels, C automatically prepends an underscore to variable names. So the C variable "foo" is actually "_foo" in assembly. You can override this with a __asm__ directive:
extern int x __asm__("led16");
will declare "x" as a C variable that matches an assembly variable named "led16" (exactly like that, no underscores). You'll still need to add a ".global led16" to the assembly language file.
Alright, I added "\t\t.global spiDummyVar" to the assembly and the new map looks like this... (spiDummyVar is at the very bottom)
spi_as.o: file format elf32-propeller
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d spi_as_cog 00000000 spi_as_cog
000004a4 l spi_as_cog 00000000 testLEDs
00000490 l spi_as_cog 00000000 negOne
00000440 l spi_as_cog 00000000 READ_CMD
00000450 l spi_as_cog 00000000 READ_CMD_ret
000004f0 l spi_as_cog 00000000 mosi
000004cc l spi_as_cog 00000000 mailbox
000004f4 l spi_as_cog 00000000 mosiPinNum
000004f8 l spi_as_cog 00000000 miso
000004fc l spi_as_cog 00000000 misoPinNum
00000500 l spi_as_cog 00000000 sclk
0000003c l spi_as_cog 00000000 LOOP
000004d0 l spi_as_cog 00000000 temp
00000494 l spi_as_cog 00000000 spiFuncBits
000000d0 l spi_as_cog 00000000 SEND
00000170 l spi_as_cog 00000000 READ
00000270 l spi_as_cog 00000000 SEND_fast
000002f8 l spi_as_cog 00000000 READ_fast
000003d8 l spi_as_cog 00000000 read_sector
00000094 l spi_as_cog 00000000 SET_MODE
000000ac l spi_as_cog 00000000 SET_BITMODE
000000b8 l spi_as_cog 00000000 SET_FREQ
000000c4 l spi_as_cog 00000000 GET_FREQ
00000454 l spi_as_cog 00000000 READ_DATA
00000464 l spi_as_cog 00000000 READ_DATA_ret
000004e4 l spi_as_cog 00000000 clkPhase
000004e0 l spi_as_cog 00000000 bitmode
00000504 l spi_as_cog 00000000 clkDelay
000004ec l spi_as_cog 00000000 data
00000468 l spi_as_cog 00000000 WRITE_DATA
00000478 l spi_as_cog 00000000 WRITE_DATA_ret
000004e8 l spi_as_cog 00000000 bitCount
00000498 l spi_as_cog 00000000 spiBitCountBits
000000dc l spi_as_cog 00000000 SEND_rd_data
0000049c l spi_as_cog 00000000 dataMask
000004dc l spi_as_cog 00000000 clock
00000110 l spi_as_cog 00000000 msb_first
000004d8 l spi_as_cog 00000000 loopIdx
0000013c l spi_as_cog 00000000 lsb_first
00000168 l spi_as_cog 00000000 SEND_complete
000001a4 l spi_as_cog 00000000 read_msb_first
0000023c l spi_as_cog 00000000 lsb_cpha1
0000026c l spi_as_cog 00000000 lsb_cpha1_ret
000001e0 l spi_as_cog 00000000 lsb_cpha0
00000210 l spi_as_cog 00000000 lsb_cpha0_ret
000001b0 l spi_as_cog 00000000 finish_lsb_first
00000214 l spi_as_cog 00000000 msb_cpha1
00000238 l spi_as_cog 00000000 msb_cpha1_ret
000001b8 l spi_as_cog 00000000 msb_cpha0
000001dc l spi_as_cog 00000000 msb_cpha0_ret
0000027c l spi_as_cog 00000000 SEND_rd_data_fast
000002a8 l spi_as_cog 00000000 msb_first_fast
000002cc l spi_as_cog 00000000 lsb_first_fast
000002f0 l spi_as_cog 00000000 SEND_complete_fast
0000032c l spi_as_cog 00000000 read_msb_first_fast
000003ac l spi_as_cog 00000000 lsb_post_fast
000003d4 l spi_as_cog 00000000 lsb_post_fast_ret
00000360 l spi_as_cog 00000000 lsb_pre_fast
00000388 l spi_as_cog 00000000 lsb_pre_fast_ret
00000338 l spi_as_cog 00000000 finish_lsb_first_fast
0000038c l spi_as_cog 00000000 msb_post_fast
000003a8 l spi_as_cog 00000000 msb_post_fast_ret
00000340 l spi_as_cog 00000000 msb_pre_fast
0000035c l spi_as_cog 00000000 msb_pre_fast_ret
000003d8 l spi_as_cog 00000000 read_sector_addr
000004a0 l spi_as_cog 00000000 sdSectorSize
000003e8 l spi_as_cog 00000000 beginSectorRead
000003ec l spi_as_cog 00000000 read_byte
00000418 l spi_as_cog 00000000 POST_CLOCK
00000428 l spi_as_cog 00000000 POST_CLOCK_ret
0000042c l spi_as_cog 00000000 PRE_CLOCK
0000043c l spi_as_cog 00000000 PRE_CLOCK_ret
0000046c l spi_as_cog 00000000 write_loop
0000047c l spi_as_cog 00000000 SEND_TO_LED
000004d4 l spi_as_cog 00000000 temp2
0000048c l spi_as_cog 00000000 SEND_TO_LED_ret
000004a8 l spi_as_cog 00000000 led16
000004ac l spi_as_cog 00000000 led17
000004b0 l spi_as_cog 00000000 led18
000004b4 l spi_as_cog 00000000 led19
000004b8 l spi_as_cog 00000000 led20
000004bc l spi_as_cog 00000000 led21
000004c0 l spi_as_cog 00000000 led22
000004c4 l spi_as_cog 00000000 led23
000004c8 l spi_as_cog 00000000 quarterSecond
00000000 *UND* 00000000 spiDummyVar
00000000 *UND* 00000000 dira
00000000 *UND* 00000000 par
00000000 *UND* 00000000 outa
00000000 *UND* 00000000 cnt
00000000 *UND* 00000000 ina
I notice its label is very different from all the others. For one, the address is 0, and two, it's got "*UND*", which to me means nothing. Googling that didn't help a lot either.
I then added "extern int dummyVarToForceLoadOfSPI_AS_S __asm__("spiDummyVar");" and it didn't help. I added that line to SPI_Demo.c and set it to 1 in main() so that the compiler didn't optimize anything away.
Still no luck.
It is very cool to look through the map of the executable though and see exactly which functions are being pulled from libc.a without me knowing. It ought to help me optimize code size by 1) knowing that function X is being included when I don't want it, and 2) knowing that function Y must be included for function A, so I might as well take advantage of it everywhere else too.
I notice its label is very different from all the others. For one, the address is 0, and two, it's got "*UND*", which to me means nothing. Googling that didn't help a lot either.
"**UND**" means "undefined". In the assembly file you have to both have the ".global" declaration (which says make the given symbol global") *and* a definition of the value for the symbol. This can be a label or an equate.
I didn't realize the expression following .global was supposed to be a symbol defined somewhere else. I thought .global would define a new global symbol.
Top of the assembly file now looks like this
.section spi_as_cog, "ax"
.compress off
org 0
.global _SPI_DUMMY_VAR
_SPI_DUMMY_VAR jmp #_SPI_DUMMY_VAR
or dira, testLEDs '' DEBUG: LEDs used for debugging purposes, can be removed later
wrlong negOne, par '' Inform parent cog that initialization has begun
// Global variables
extern uint32_t _start_spi_as_cog[];
And fixed up SPI_Demo.c
extern uint32_t SPI_DUMMY_VAR[];
with a reference in main:
in = SPI_DUMMY_VAR;
And that worked, but now, new errors have popped up.
OUTPUT(SPI_Demo.elf elf32-propeller)
../../../Debug/libPropWare.a(spi_as.o): In function `_SPI_DUMMY_VAR':
(spi_as_cog+0x0): relocation truncated to fit: R_PROPELLER_SRC against symbol `_SPI_DUMMY_VAR' defined in spi_as_cog section in ../../../Debug/libPropWare.a(spi_as.o)
../../../Debug/libPropWare.a(spi_as.o): In function `_SPI_DUMMY_VAR':
(spi_as_cog+0x4): relocation truncated to fit: R_PROPELLER_SRC against `testLEDs'
../../../Debug/libPropWare.a(sp........................
..........................
...........................
Google tells me that this happens when the program is so large, it exceeds the addressable memory (like a 5 GB program running on a 32-bit system).
Would this be the same error that shows up when a prop program exceeds it's 32kB max? Either case doesn't make sense since there's no way my program is that large.
I think only sections that end in ".cog" are recognized as COG sections by the linker; "_cog" will be treated as a regular data section and linked into HUB memory (hence the overflows, the HUB addresses are too big to fit in the 9 bit fields in the PASM assembly).
@David Betz: I'd still love to hear how you got around this in your libraries. Though I now have it working, it requires not only the "extern int dummyVar[]" at the top of the file, but I must also reference that variable in a useful fashion in the driver program (aka, "int x = dummyVar" as the first line of main() isn't good enough). This is horrible and ugly and I don't want to force users of PropWare to do this.
I suppose one way to get around it is to move "extern __load_start_spi_as_cog[];" into spi.h and pass that address in as a parameter to SPIStart(). Probably prettier than the current solution, but not ideal.
The root of the problem is that you always need to include the assembly language section if you're linking the C interface. So there are a couple of more elegant ways to force this:
(1) Do a partial link of spi.o (the C interface) and spi_as.o (the COG assembly code) using the -r option to propeller-elf-ld. Call the result something like spi_combined.o, and put that file in the library instead of spi.o and spi_as.o. That way the C and assembly are always pulled in together.
(2) Even easier (but perhaps slightly less flexible): put the code to launch the COG in the assembly file, instead of in the C file. You'd do this by adding something like:
'' function to start the SPI code in its own COG
'' C interface is:
'' int start_spi_cog(void *arg);
'' returns the number of the COG, or -1 if no COGs are left
.text
.global _start_spi_cog
_start_spi_cog
mviw r7,#__load_start_spi_as_cog '' linker magic for the start of the spi_as.cog section
shl r7, #2
or r7, #8 '' 8 means "first available cog
shl r0, #16 '' assumes bottom two bits of r0 are 0, i.e. arg must be long aligned
or r0, r7
coginit r0 wc,wr
IF_B neg r0,#1 '' if C is set, return -1
lret
to the end of spi_as.S (after the .compress default). This is perfectly legal; the code is marked as .text, so the linker will know it should go in the HUB instead of in the COG memory.
Then replace the cognew() in spi.c with something like:
extern int start_spi_cog(void *arg);
...
cogid = start_spi_cog(&g_mailbox);
This has several advantages: it hides the whole _load_start_spi_as_cog stuff inside spi_as.s, and also provides a symbol (_start_spi_cog) that will force spi_as.o to be linked.
I'm getting undefined reference errors with your second suggestion. Namely:
/home/david/External/Kits/Embedded/Parallax/Library/PropWare/lmm/libPropWare.a(spi_as.o): In function `_SPIStartCog':(.text+0x20): undefined reference to `__LMM_lret_ret'
/home/david/External/Kits/Embedded/Parallax/Library/PropWare/lmm/libPropWare.a(spi_as.o): In function `_SPIStartCog':
(.text+0x20): undefined reference to `__LMM_lret'
I've seen similar errors before, and it happened when some files had been compiled in lmm mode, other files were compiled in cmm mode, and then the two different files were linked against each other in the executable. I checked as carefully as I could though to be sure that all files were compiled with the correct code and, as far as I can tell, it's setting the correct mode.
I've created two more branches based on development: dev_asm_hack and dev_link_hack. Your second suggestion and my attempt at implementing it is pushed to dev_asm_hack and your first suggestion will be implemented momentarily in dev_link_hack.
I've decided to remove the "Debug" folder from project root and go with a non-eclipse-based build system. "make" can now be run directly from the project root and it will build the library in cmm, xmm, and lmm modes. common.mk includes the proper version based on what "model" is set to.
Slowly but surely, I feel this project is going in the right direction... I'd love to see it get used by lots, but even if it doesn't, I'm certainly learning a lot by building this from the ground up! Thanks for all the help!
I'm getting undefined reference errors with your second suggestion. Namely:
/home/david/External/Kits/Embedded/Parallax/Library/PropWare/lmm/libPropWare.a(spi_as.o): In function `_SPIStartCog':(.text+0x20): undefined reference to `__LMM_lret_ret'
/home/david/External/Kits/Embedded/Parallax/Library/PropWare/lmm/libPropWare.a(spi_as.o): In function `_SPIStartCog':
(.text+0x20): undefined reference to `__LMM_lret'
Ah, that was a bug in the assembler's handling of the "lret" macro. It's been fixed in the Google code repository, but I'm not sure if it's made it to release yet. You can replace lret with something like:
#ifdef __PROPELLER_CMM__
lret
#else
mov pc, lr
#endif
I've seen similar errors before, and it happened when some files had been compiled in lmm mode, other files were compiled in cmm mode, and then the two different files were linked against each other in the executable.
As I'm sure you know, mixing LMM and CMM will fail in all kinds of ways :-). I think the most recent linker should explicitly warn you about that.
/* mviw expands to a jmp followed by a 32 bit constant, just like fcache */ {"mviw", 0x5c000000, 0xffffffff, PROPELLER_OPERAND_MVI, CCZCNR, PROP_1_LMM, COMPRESS_MVIW, PREFIX_MVIW},
LMM mode now works great. CMM mode is broken though, throwing an undefined reference on "mviw r7, #__load_start...". Based on how you simply replaced lret, I thought I'd do the same with this instruction but I don't know what this "32 bit constant" is that opc.c is referring to. Why would any instruction be followed up with -1?
/* mviw expands to a jmp followed by a 32 bit constant, just like fcache */ {"mviw", 0x5c000000, 0xffffffff, PROPELLER_OPERAND_MVI, CCZCNR, PROP_1_LMM, COMPRESS_MVIW, PREFIX_MVIW},
LMM mode now works great. CMM mode is broken though, throwing an undefined reference on "mviw r7, #__load_start...". Based on how you simply replaced lret, I thought I'd do the same with this instruction but I don't know what this "32 bit constant" is that opc.c is referring to. Why would any instruction be followed up with -1?
All of your libraries are built with CMM mode or LMM mode and nothing is mixed?
I had no idea that assembly needed to be built with a memory model. After adding -m$(MODEL) to the assembler flags, it's working now. I guess for cmm mode, it makes sense.
I had no idea that assembly needed to be built with a memory model. After adding -m$(MODEL) to the assembler flags, it's working now. I guess for cmm mode, it makes sense.
Indeed, CMM mode uses its own instruction set (which is interpreted by the CMM kernel). The assembly language is very similar, because CMM allows any LMM instruction to be encoded, but the binary output of the assembler is completely different in CMM mode.
With the library now working, I've merged it into master and updated the documentation. I think it's much better than before, but I'm sure there's room for improvement. Suggestions welcome as always. http://david.zemon.name/professional/PropWare/docs/html/
Comments
You're not confused.
This happens with SimpleIDE libraries.
Sorry, but my time is very limited today so I can't help more than I have already.
Perhaps David will help since he created common.mk.
Oops. I just noticed that you've already provided a link to a GitHub repository. I'll pull the code and see if I can figure out what's going wrong.
Edit: Sorry again. I guess I'm not sure what question I'm supposed to answer. What are you trying to do with common.mk that is giving you trouble?
The way around this is to refer to *some* symbol in the .o file you want linked. For example, you could place an initialization function that loads the COG in there. Or you could declare a mailbox variable that your main C code uses. Anything at all -- but it has to be an explicit symbol, not something like _load_start_xxx.
Hope this helps.
If I understood that correctly (which I'm not 100% sure I did), I'm already doing that. libPropWare.a contains spi.c and spi_as.S. Those two files contain driver code for SPI comms, including the cog initialization (line 86 of spi.c). My demo application contains SPI_Demo.c and, within this file, I call SPIStart() from spi.c. I believe that call is what you're suggesting - something from outside the library calls an explicit label (that label is _SPIStart in this case) and then an internal function relative to the library file can start the cog.
Uploading a zip file momentarily...
Creation of the library can be done from within the Debug folder with "make -f../Makefile" (you'll need to set the PROPGCC_PREFIX variable in Makefile) and then the same command can be run from PropGCC_Demos/SPI/Debug with the same addition to PropGCC_Demos/SPI/Makefile. I did it this way so that it plays nicely with Eclipse and requires minimal changes to the default settings for any Eclipse CDT build.
The problem you're encountering is that you want spi_as.o to be linked, but the only reference to it is the implicit label _load_start_spi_as. That label doesn't actually exist anywhere in the object files, it is created by the linker when the spi_as_cog section is encountered. That leads to a chicken and egg problem -- the spi_as_cog section won't be included because there's no reference to anything in spi_as.o. You'll have to create some kind of dummy reference in spi_as.o to force it to be linked.
That's not working though. I thought maybe the compiler was optimizing that line out, so I stuck a simple "int x = *led16" at the top of SPI_Demo.c's main function and it didn't help any either. Perhaps it's still optimizing it out?
Also, I've attached the map file of libPropWare.a for reference
(1) led16 is not marked as ".global", and so its definition is local to that specific .o file (like a C "static" variable). It can't be referenced from outside.
(2) There's another wrinkle: to avoid conflict with assembly language labels, C automatically prepends an underscore to variable names. So the C variable "foo" is actually "_foo" in assembly. You can override this with a __asm__ directive: will declare "x" as a C variable that matches an assembly variable named "led16" (exactly like that, no underscores). You'll still need to add a ".global led16" to the assembly language file.
I then added "extern int dummyVarToForceLoadOfSPI_AS_S __asm__("spiDummyVar");" and it didn't help. I added that line to SPI_Demo.c and set it to 1 in main() so that the compiler didn't optimize anything away.
Still no luck.
It is very cool to look through the map of the executable though and see exactly which functions are being pulled from libc.a without me knowing. It ought to help me optimize code size by 1) knowing that function X is being included when I don't want it, and 2) knowing that function Y must be included for function A, so I might as well take advantage of it everywhere else too.
Top of the assembly file now looks like this So that's good!
SPI_Demo.elf's map contained
So I changed the top of spi.c to look like
And fixed up SPI_Demo.c with a reference in main:
And that worked, but now, new errors have popped up.
Google tells me that this happens when the program is so large, it exceeds the addressable memory (like a 5 GB program running on a 32-bit system).
Would this be the same error that shows up when a prop program exceeds it's 32kB max? Either case doesn't make sense since there's no way my program is that large.
Eric
Thanks for your help and patience Eric!
@David Betz: I'd still love to hear how you got around this in your libraries. Though I now have it working, it requires not only the "extern int dummyVar[]" at the top of the file, but I must also reference that variable in a useful fashion in the driver program (aka, "int x = dummyVar" as the first line of main() isn't good enough). This is horrible and ugly and I don't want to force users of PropWare to do this.
I suppose one way to get around it is to move "extern __load_start_spi_as_cog[];" into spi.h and pass that address in as a parameter to SPIStart(). Probably prettier than the current solution, but not ideal.
(1) Do a partial link of spi.o (the C interface) and spi_as.o (the COG assembly code) using the -r option to propeller-elf-ld. Call the result something like spi_combined.o, and put that file in the library instead of spi.o and spi_as.o. That way the C and assembly are always pulled in together.
(2) Even easier (but perhaps slightly less flexible): put the code to launch the COG in the assembly file, instead of in the C file. You'd do this by adding something like: to the end of spi_as.S (after the .compress default). This is perfectly legal; the code is marked as .text, so the linker will know it should go in the HUB instead of in the COG memory.
Then replace the cognew() in spi.c with something like: This has several advantages: it hides the whole _load_start_spi_as_cog stuff inside spi_as.s, and also provides a symbol (_start_spi_cog) that will force spi_as.o to be linked.
I've seen similar errors before, and it happened when some files had been compiled in lmm mode, other files were compiled in cmm mode, and then the two different files were linked against each other in the executable. I checked as carefully as I could though to be sure that all files were compiled with the correct code and, as far as I can tell, it's setting the correct mode.
I've created two more branches based on development: dev_asm_hack and dev_link_hack. Your second suggestion and my attempt at implementing it is pushed to dev_asm_hack and your first suggestion will be implemented momentarily in dev_link_hack.
I've decided to remove the "Debug" folder from project root and go with a non-eclipse-based build system. "make" can now be run directly from the project root and it will build the library in cmm, xmm, and lmm modes. common.mk includes the proper version based on what "model" is set to.
Slowly but surely, I feel this project is going in the right direction... I'd love to see it get used by lots, but even if it doesn't, I'm certainly learning a lot by building this from the ground up! Thanks for all the help!
Eric
All of your libraries are built with CMM mode or LMM mode and nothing is mixed?
Indeed, CMM mode uses its own instruction set (which is interpreted by the CMM kernel). The assembly language is very similar, because CMM allows any LMM instruction to be encoded, but the binary output of the assembler is completely different in CMM mode.
Glad you got that sorted out!