Jump to content


  • Content Count

  • Joined

  • Last visited

Community Reputation

0 Neutral

About PhracturedBlue

  • Rank
  1. I was upgrading some code I wrote in 2005 before bitwise variable access was supported (ie var.3). I have a piece of code which is: var ^= 1 << 1; (I guess this is the same as the 'toggle_bit' macro which I'm not sure existed back in 2005, or if I just didn't know about it) which gets compiled to: MOVLW 0x02 XORWF gbl_var, F but when I changed it to: var.1 ^= 1; I get MOVF gbl_var, W XORLW 0x02 MOVWF gbl_var Both are functionally equivalent, but the 1st is slightly more optimal. I was just surprised at the difference. The code following this relaods W with a different value, so there is no optimization of W going on in either case. It is certainly not a big deal, but is it what I should expect?
  2. I have generated the following test-case which demonstrates something that I ran into: #include <system.h> void main() { char a=0; while(1) { a|=portb; if(test_bit(a,0)) goto reset; if(0) { reset: a=0; } a<<=1; } } When I compile this, it compiles fine, but the linker reports: Internal Error: Unable to resolve label ID:0x1000024B apparently, the 'if(0)' is getting optimized out, so the goto fails. I am using code like this in an interrupt routine to reset a state-machine on bad input of course, I can write the code as: #include <system.h> void main() { char a=0; while(1) { a|=portb; if(test_bit(a,0)) goto reset; goto cont; reset: a=0; cont: a<<=1; } } and I'd expect the output assembly to be identical, but as far as I know the 1st method is valid C syntax, and should work correctly.
  3. While strlen, strcmp (probably should make that strncmp) would be nice, I disagree for sprintf. sprintf would have to be a monster function, unless you limited it to only a few capabilities. Just adding '%d' or '%ld' adds a large amount of code. Then there are all the formatting options. And, in the end, storing temporary strings in RAM is extremely wasteful (much better to operate on the string as you build it). At some point, it is time to remember that this is a micro-controller, and that it is better to only implement what is realy needed. Also, it is usually a bad idea to deal with strings in RAM if you have any option at all. They consume an awful lot of that precious commodity. For the others here you go. Not strictly ansi-c compliant, but good enough for most purposes. You could probably search the internet for 10 minutes, and come up with better implementations, but these wil at least work with boost-c as is. char strlen(char *a) { char i=0; while(a[i]) { ++i; if(test_bit(i,7)) break; } return(i); } signed char strncmp(char *a, char *b, char len) { char i; for(i=0; i<len; ++i) { if(a[i]<b[i]) return -1; if(a[i]>b[i]) return 1; if(! a[i]) return 0; } return(i); } signed char strncmpi(char *a, char *b, char len) { char i,tmpa; for(i=0; i<len; ++i) { tmpa=a[i]; if(tmpa>64 && tmpa<91) tmpa+=32) if(tmpa<b[i]) return -1; if(tmpa>b[i]) return 1; if(! tmpa) return 0; } return(i); } #define strcmp(a,b) strncmp(a,b, 128) #define strcmpi(,b) strncmpi(a,b,128)
  4. I have implemented something similar, though I use byte-compression to store two characters in a 14-bit word (since for text output, 0-128 is usulaly good enough). I use the flash-read capability of all (many?) Pic 16F parts to retrieve the value directly. In the case of outputting to an LCD, I use fixed length strings, which makes the code very small, but I have a general purpose mechanism too. The way it works, is that I store the string length as the first half-word in the string, and I jump to the relevant location through a series of seeks. As long as the number of elements isn't too long, it works well. In my implementation, strings need to start on a word boundary, so I pad the second half-word with '0' if the string length is even. For instance: char[] "string12" is 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x32 and the length=8, (which I store as # of additional words ((8+2)/2)-1 = 4). so I store the bytes: 0x04, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x31, 0x32, 0x00 compressed into 5 words: #pragma DATA 0x0FFB, 0x3984, 0x3974, 0x3769, 0x18E7, 0x0032 (note, I've stored the first byte in the lo half-word, so it looks backwards here) If I have an array, say: char *foo[] = {"string1", "string12"}; This ends up as: #pragma DATA 0x0FF7, 0x3983, 0x3974, 0x3769, 0x18E7, 0x3984, 0x3974, 0x3769, 0x18E7, 0x0032 The code to process this looks like: char lo, hi; void readFromRom() { set_bit(eecon1, EEPGD); set_bit(eecon1, RD); nop(); nop(); hi=eedath; hi<<=1; lo=eedata; if(test_bit(eedata, 7)) set_bit(hi, 0); eeadr++; if(! eeadr) eeadrh++; } void sendFromRom(unsigned short addr, char index) { eeadrh=addr>>8; eeadr=addr; char i; for(i=0; i<=index; ++i) { readFromRom(); if(i<index) if(eeadr > (eeadr+=lo)) eeadrh++; } sendChar(hi); index=lo; for(i=0; i<index; ++i) { readFromRom(); sendChar(lo); if(ret_hi) sendChar(hi); } } The you just call as: sendFromRom(0xFF7, 1), and it will call sendChar with: 's', 't', 'r', 'i'. 'n', 'g','1',2' I use the following perl code to generate the byte compressed code: #!/usr/bin/perl -w $memsize=hex(shift @ARGV); $arg=""; $pos=$memsize; while (@ARGV) { $str=shift @ARGV; if(! length($str)%2) { $str.='\0'; } $pos-=(length($str)+1)>>1; $arg.=sprintf("%c", -1 + (length($str)+1)>>1) . $str; } @a=split //, $arg; #$pos=$memsize-(length($arg)>>1); $str=sprintf("#define ROM_ADDR 0x%04X", $pos); $str1=sprintf("#define ROM_ADDR 0x%04X", $eeprom_start); for($i=0;$i<(scalar @a);$i+=2) { if($i%16==0) { $str.="\n"; $str.=sprintf("#pragma DATA 0x%04X", $pos); $pos+=8; } if ($i==$#a) { $str.=sprintf(", 0x%04X", ord($a[$i])); } else { $str.=sprintf(", 0x%04X",(ord($a[$i+1])<<7)| ord($a[$i])); } } print "$str\n"; call as: build_pragma.pl 0xfff "string1" "string2" the 0xfff is the upper end of memory (I store the rom at the end of the availiable ROM). Note, the above may not be exactly correct. I had to modify my actual code in the above post to make it general-purpose. This byte compressed implementation takes ~ #chars/2+1 code-words to store a string, which is pretty efficient when storing many strings in a small space. I don't know if anyone will find this useful or not, but perhaps. It would be cool if boostC could do this for me (especially the byte-compressing), but it is probably too special-purpose for that to happen. FWIW, Microchip's assembler supports the DBA keyword, which will turn: DBA "string1" into a byte-compressed words for this very purpose.
  5. I find the SourceBoost IDE to be a nice environment to work in, but the following enhancements would make it a lot nicer: 1) only rebuild what is needed. Today, the IDE will either rebuild nothing (if I haven't edited anything), or all source files (if I have changed anything at all). Correctly detecting changes, and only rebuilding files that have changed (or which reference headers that have) would be convenient. 2) link asm/lst/c views together. It would be very nice to be able to select a line in c-source, and jump to the corresponding line in asm/lst view (and vice-versa) 3) It would be very convenient to have a 'find again' hotkey (perhaps Ctrl-G). This is especially annoying, as Ctrl-F selects whatever is under the cursor, so if I do a search, move the cursor, and then want to do the same search again, I need to retype the search string. Just some ideas.
  6. If a function's input parameter is defined as 'const' I'd think that in many cases the copy could be optimized away as in: void foo(const unsigned int a) { ... } void bar() { unsigned int b; b= ... ... foo(b); ... } Today, boostC will generate something like: ; bar movlw ... movwf _bar_b movlw ... movwf _bar_b+1 ... movf _bar_b, W movwf _foo_a movwf _bar_b+1, W movwf _foo_a+1 call foo ... but this should not be too hard to optimize (in many situations) to: _foo_a equ 0x0000005f _bar_b equ 0x0000005f ;bar movlw ... movwf _bar_b movlw ... movwf _bar_b+1 ... call foo ... sure it is only 4 instructions, but I have cases in my code where these types of things eat a lot of code space. I can trade RAM for code size by making the variables global, but there is no reason to do this in many cases, especially if the compiler has already determined how to overlap temporary variables to minimize RAM usage.
  7. I'd like to do something like the following: void foo(char &a, char &b) { //Do something which changes both a and b a++; b++; } void bar() { char a=1, b=1; foo(a, b); //now a=2, b=2 } I can do this using ponters void foo(char *a, char *b) { *a++; *b++; } void bar() { char a=1, b=1; foo(&a, &b); } but the assembly code for this looks horrendous (of a PIC16) whereas for what I want, the code would look something like: ;foo incf _foo_a incf _foo_b ; end of foo ; bar movlw 1 movwf _bar_a movwf _bar_b movw _bar_a movw _foo_a movw _bar_b movw _foo_b call foo movw _foo_a movw _bar_a movw _foo_b movw _bar_b ;end bar This would be a convenient way to return multiple values from a function. Of course in the above example, I could get away with returning an 'int', and unpack it, or I could use global variables, etc, etc. But isn't the above standard c, and shouldn't it be supported?
  8. However, I came up with a different solution, (at least for the writer) that works equally well, and actually delas with the interrupts correctly: void write_eeprom(char addr, char data) { char int_on; while(test_bit(eecon1, WR)) ; eeadr=addr; eedata=data; clear_bit(eecon1, EEPGD); int_on=(test_bit(intcon, GIE)); clear_bit(intcon, GIE); set_bit(eecon1, WREN); eecon2=0x55; eecon2=0xaa; set_bit(eecon1, WR); if(int_on) set_bit(intcon, GIE); clear_bit(eecon1, WREN); } by swapping the clear_bit(intcon, GIE) and the set_bit(eecon1, WREN) I was able to prevent the bank-switch which was getting in the way of the 5-critical-instruction block Plus my code actually handles the interrupt apropriately (though it does consume 1 byte of RAM). I think fransp's example (perhaps with my write routine?) should be added to the boostC examples directory, as this must be a common issue, and it took some tweaking to get it to work correctly.
  9. Since noone answered you, perhaps this will help: Have you tried using pointers to do this? set a pointer at the beginning of the bank, and just use an offset to get any address you want . For instance: char *ptr; for(ptr=0x00;ptr<128;ptr++) { print_char(*ptr); } A problem with this method: you can only do a single bank at a time, so you'll need several pointers. the SPRs will be intermixed in this, and in some cases reading them will change their behaviour (on some chips, reading portb resets the latch, for instance) alternatively, you could do it in an asm{} more easily, though BoostC may not like you playing with the status register. Note that the above applies to the 16F series. I haven't used the 18F. If it doesn't use banks for RAM access, the above method should be pretty easy. Good luck
  10. You are correct, that you will get these DW in the .asm, and .hex file. But when you program it onto the PIC (or even load it into a simulator), you'll find that it actually assignes the values to each byte, as if you had used a DB. So though the result looks odd, it works fine for writing to EEPROM. If you wnat to write to Program memory using '#pragma DATA' you need to write full 14bit words though. For instance, I was doing byte-compression (place 2 ASCII characters into a single 14bit word) similar to the 'DA' directive in MPASM, and I couldn't figure any way to do it through boostC. I ended up writing a perl script to pack strings for me, and just used '#pragma DATA' to get around this.
  11. What are you trying to do? trisb doesn't actually change the value of portb, it just determines whether it is an input or an output. you probably meant something like: set_bit(portb, 4); delay_ms (750); clear_bit (portb,4 ); note that set_bit/clear_bit take a number 0-7, not the bitmask.
  12. So this is definitely a bug (using the ptr method) since the code compiles cleanly with no relevant warning/error, and the rom data is not getting stored. The code in my second post can be used as a test case. I tested your example, and it seems to work fine. Thanks. I'm so used to working with pointers, I didn't think of that. I may actually use the 'flash read' method specified in the 16f88 datasheet instead though, since I can fit 2 ascii characters into a 14bit word, it will take half as much ROM for my string.
  13. yes that works. well no error/warning during comiling. During linking I get this: Warning: cannot symbolize, no COFF equivalent data type for variable: 'ptr' which is probably telling me there is a problem, though I still get 'Success' so I didn't notice this at first. Can you think of a better way to implement my example? I have a large number of strings, so it will waste a lot of ram if I need to define them each individually (each string ends up as its own variable, and takes a byte). My thoughts at the moment are to build my own jump-table rom implementation in ASM for my array of strings.
  14. Sorry, that was a poor example. Here is one which doesn't actually work: #include <system.h> rom char *ptr="This is a very long text string"; void main() { char buf1; char* buf; buf=ptr+5; buf1=buf[0]; } The asm looks like: main ; { main; function begin MOVLW 0x05 BCF STATUS, RP0 BCF STATUS, RP1 ADDWF gbl_ptr, W MOVWF CompTempVar36 MOVF gbl_ptr+D'1', W MOVWF CompTempVar37 BTFSC STATUS,C INCF CompTempVar37, F MOVF CompTempVar36, W MOVWF main_1_buf MOVF CompTempVar37, W MOVWF main_1_buf+D'1' BCF STATUS,IRP BTFSC main_1_buf+D'1',0 BSF STATUS,IRP MOVF main_1_buf, W MOVWF FSR MOVLW 0x00 ADDWF FSR, F MOVF INDF, W MOVWF main_1_buf1 RETURN ; } main function end ORG 0x0000001A _startup MOVLW 0x00 BCF STATUS, RP0 BCF STATUS, RP1 MOVWF gbl_ptr BCF PCLATH,3 BCF PCLATH,4 GOTO main END no reference to rom_get or the string. Are pointers to rom objects not supported? What I am tyring to do is emulate this: rom char *[] str = {"Test1", "Test2"}; ... my_fun(str[i]); which doesn't work, because roms can only be strings. So I do it this way: rom char* str = "Test1" "Test2"; //strings have a fixed length ... char *ptr=str+(5*i); my_fun(ptr);
  15. I am trying to use rom storage with boostC, but it doesn't work. This is for a 16F88 processor #include <system.h> rom char *ptr="This is a very long text string"; void main() { } and the resulting asm: ORG 0x00000000 GOTO _startup ORG 0x00000003 main ; { main; function begin RETURN ; } main function end ORG 0x00000004 _startup MOVLW 0x00 BCF STATUS, RP0 BCF STATUS, RP1 MOVWF gbl_ptr BCF PCLATH,3 BCF PCLATH,4 GOTO main END Any ideas?
  • Create New...