
stryd_one
Frequent Writer-
Posts
8,840 -
Joined
-
Last visited
-
Days Won
1
Content Type
Profiles
Forums
Blogs
Gallery
Everything posted by stryd_one
-
George Bush isn't stupid and neither are you... But your guess was about as right as he is a good speaker ;D You'll need to wrap the ASM that qbas sorted out into the main.c, using techniques like those at the How to mix C and ASM wiki page, or include the ASM file in your C project, using techniques like the using assembler in C - question about _ in front of macro names post :) Feel free to post/PM/email me for a hand.
-
Geez that could be really nice, good luck bro :)
-
Front Panel Express :)
-
LOL :D Ta for the advice mate. It is a kinda old concept and the implementation of a few types is already figured out, but I just haven't mentioned it before. It's funny though, because I have all these scrapbooks that I write ideas in, and I think that's the only one that never got written down. I just kept remembering it at inconvenient times, until yesterday when I sent that post. It's got spooky karma... I'm leaving it till later, as it seems it wishes ;)
-
Yeh exactly. It just finds the method that uses the least instructions to get the correct answer. I guess it makes sense but it wasn't what I expected to find. ; .line 149; main.c bstest = bstest << 5; SWAPF _bstest, W, B ANDLW 0xf0 MOVWF _bstest, B ADDWF _bstest, F, B ; .line 149; main.c bstest = bstest << 7; RRCF _bstest, W, B CLRF _bstest, B RRCF _bstest, F, B Weird, but good :)
-
Check out QBAS's code for a velocity sensitive scan matrix. Search for qbas keyboard and you'll see it :) Tell us more about these keybeds :D
-
Ahh that explains it. Damn standards. If I were Bill Gates I could ignore this. ;D I had a look at it and was interested to find out that it always uses the carry bit when it rotates - but in a lot of cases for shifts of static magnitude it doesn't use R*CF at all - like for <<2, it does an ADDLW to double the number... Where the magnitude of the shift is variable, it will use that variable as a counter, and uses a rotate (with carry) . Where the variable being shifted is > 8bit then it uses rotate with carry always.
-
Just a quick followup - indeed, SDCC will only allow declarations to be made at the very top of the function before it actually does anything... as for negating the variable... a NEGF instruction would have done fine. D'oh!
-
Lucky you ;) I wonder, does your supplier have other grayhill switches on the cheap?
-
Now that I've sorted the big banks issue I thought I might mention an idea I had... Nonlinear clocks. Basically instead of going like this x.......x.......x.......x.......x.......x....... We could have this x.........x.......x.....x...x...x. or this x..............x.......x...x.x.x...x......x...............x or this x.x..x....x........x................x........x....x..x.x etc etc. Now of course this is a clock, so the calculation of the gaps (...) between triggers (x) needs to be fast. Bitshifts instantly come to mind, and I was thinking about combining bitshifts with addition and subtraction, anyone have any ideas?
-
Thanks man. Last thing I need is the stress of blowing my stack ;)
-
Spot the automation junkie ;D hehehehe
-
hehehe yeh I went on a mission to figure out a problem, and found three more while I was there :P I could use naked ASM there but I'm trying to keep it portable where I can... I'll experiment today and see what it does with an unsigned char...
-
Darn :'(
-
Thx for the advice mate :)
-
Before I try this and fail and waste my time, has anyone else tried to implement recursive functions? Any luck?
-
LOL :) Yeh RTFM isn't necessarily the best thing around for plain english about it either :P Ahh it's like this...I'll just do right shift as an example. The way it does a bitshift is really a bit rotation. Without the Carry bit, when you rotate right, the bottom bit doesn't just drop away, it gets pushed onto the top of the byte: v 0110 1001 >> 1 = 1011 0100 ^ That's an RRNCF - Rotate Right No Carry F However with the Carry Bit, there is one extra bit, and the bit that gets pushed off the end of the byte goes there: C v 0 0110 1001 >> 1 = 1 0011 0100 ^ If you continue to shift (OK rotate) after this without clearing the status bit, then it rolls back onto the byte: C v 1 0011 0100 >> 1 = 0 1001 1010 ^ That's an RRCF - Rotate Right through Carry F There are ways around it, but if you want one type of rotation, and are forced to use the other, it'll cost one instruction to get the same effect. Here's an example. scpbtemp is a long type (32b). I wrote this: STATUSbits.C = 0; //Clear Carry Bit scpbtemp = scpbtemp >> 1; And SDCC produced this: ; .line 40; vxscpb.c STATUSbits.C = 0; //Clear Carry Bit BCF _STATUSbits, 0 ; .line 41; vxscpb.c scpbtemp = scpbtemp >> 1; BCF STATUS, 0 RRCF r0x06, F RRCF r0x05, F RRCF r0x04, F RRCF r0x03, F Notice that it cleared the status bit twice - once when I told it to, and once all by itself. This is a good demonstration of use for the carry bit... It gets pushed onto the top of each successive lower byte of the 32 bits. This is why the Carry bit needs to be cleared, atherwise some random value from another function might be pushed onto our variable, and may be why SDCC chose to use RRCF rather than RRNCF... Or it might just always use it.. I can find out, but I was hoping someone might have come across it. But I don't like that it assumed I want that bit clear... Maybe I want the carry bit to be sent from another function? Then what? ??? Hmmmmmmm.....
-
Hmmm Midibox stopped working Please Help.
stryd_one replied to sidetrack's topic in Testing/Troubleshooting
Yeh I think sidetracked is sorted now. Thanks for the insight on the hardware man :) It is nooot my strong point! -
An answer to the extended databanks problem
stryd_one replied to stryd_one's topic in MIOS programming (C)
Well a #define would probably effect the whole file because it's pre-processor, so you could use --obanksel=1 to avoid it for the same effect - in fact this is how I got the example code with both banksel's in it :) BTW, if you do need to do that, don't change it in the makefile.spec: that will do it for all files and make big slow code; instead, run make, let it create the makefile and compile, then edit makefile, and change the switch only for the required files. I was thinking of something like the __ASM flags, like __obankseloff and __obankselon... Maybe I should request it :) -
Check out Sasha's design he just posted for a virus like desktop layout :)
-
Bloody koalas get in the way of the words ;D
-
Damn you make a good lookin CS dude!!
-
Hmmm Midibox stopped working Please Help.
stryd_one replied to sidetrack's topic in Testing/Troubleshooting
I love your posts but every time I read one, I get all interested, and it costs me an hour of surfing ;) I think we might have gotten a bit sidetracked. Get it? Sidetrack? the OP? ahhh nevermind. Say hi to my old russian friend. ;D -
Hey you crazy coders. Great to see lots of buzz about user developed apps around here at the moment :) I hope someone might know a trick for me.... if I use a bitshift in C with the >> or << operators, then the ASM generated is a RRCF or RLCF. These both use the Carry bit (statusbits.C aka STATUS.0). The carry bit is cleared before the shift even if I don't specify it :( Is there a way to have C generate a RRNCF or RLNCF instead? There are certain cases where I'd be better off without it... Is there a way to NOT clear the carry bit before a bitshift? While I'm on the subject of bitfields, I wonder if anyone has tried this and might be able to save me a few hours experimenting...Which is faster in a FOR loop: Declare your bitfield in a union as normal Test bit 'n' in the loop or... Declare the bitfield as a normal char, bitshift, and test the carry bit Once upon a time I remember TK saying that bitfields could slow things down, but looking at the generated code, I suspect that the newer versions of SDCC may have fixed that problem. For example, 'statusbits.C = 0' becomes 'BCF STATUS.0'... And I think I remember AC saying that bitfields are limited to 8 bit? Lootts of questions....
-
Hey crew. I nutted something out today which I hope will be helpful. It's been a M****F******** thorn in my side for the entire coding of the vX so far, so I'm stoked that I've nutted it and I hope this long post will help you avoid the same pain. I've thrown in a couple of other memory handling and performance specifics that came up along the way too. <Ramblings of a tormented developer> Most of you would have come across the "maybe it works, maybe not, nobody is too sure WTF it does" method of storing large sets of data (>256), by combining databank entries in the linker script. Those who have tried it, will find that it sometimes works like a charm, and sometimes not. Here's why, with code snippets from the vX as examples of what not to do hehehe OK the example will be the track struct. I won't post the code for it here just yet, but suffice to say, it's big and complex with different types all through it, 100% yuck. Now with no pragma marks set, the compiler will name the variable "udata_<filename of declaration>_n". You can see it in output\main.asm like so: udata_main_1 udata _track res 314 //////////// See Note Below that 314 is the number of bytes used in decimal. It's two tracks, each 157B. Obviously they can't fit in a standard bank, so I extend the first bank in the linker: // DATABANK NAME=gpr0 START=0x080 END=0x0FF // DATABANK NAME=gpr1 START=0x100 END=0x1FF DATABANK NAME=gpr01 START=0x080 END=0x1FF The result is that the struct is stored in that space, which can be seen in the project.map file: udata_main_1 udata 0x000080 data 0x00013a All good right? Well... That depends. Let's say we have a for loop which goes through all the tracks playing step 0 (of course you wouldn't do that but just for example) for (i = 0;i < 16;i++) { MIOS_MIDI_TxBufferPut(track[(i)].step[0].param1) } If you do that, then the variable could point to different addresses in ram, depending on the value of 'i'. Microchip direct that "Indirect addressing is a mode of addressing data memory, where the data memory address in the instruction is not fixed." - and as this is the case here, the compiler will use indirect addressing. This works by calculating the memory location (aka pointer math) filling two registers with the memory address which was calculated and then finally reading from that address. This method of memory access does not require bank selection, but setting the address can be a costly process. Here's an example where the pointer math results in an address stored in r0x00 and rx02: MOVFF r0x00, FSR0L ; Low byte of the address MOVFF r0x02, FSR0H ; High byte MOVFF INDF0, r0x00 ; Move byte from indirect file access register to temporary register MOVF r0x00, W ; Move to W and send the byte via midi. CALL _MIOS_MIDI_TxBufferPut Check out section 4.12 in the 452 datasheet for more, but the news here is all good. Because the memory of the PIC is seen by the indirect addressing scheme as one great big pool, it does not have any problem with crossing over the 256B banks, and if multiple bytes in successive addresses need to be read, the pointer math only gets done for the first address, and then the pointer can be incremented or decremented automatically. See 4.12.1. Let's say I have these two lines in the code to initialise the note number that the first step in track 0 and 1 should play. track[0].step[0].param1 = 0x50; track[1].step[0].param1 = 0x40; In this case, the memory location does not change for these functions, and so banked memory access will be used. The ASM output looks like this: ; .line 100; main.c track[0].step[0].param1 = 0x50; MOVLW 0x50 BANKSEL (_track + 20) MOVWF (_track + 20), B ; .line 101; main.c track[1].step[0].param1 = 0x40; MOVLW 0x40 BANKSEL (_track + 178) MOVWF (_track + 178), B Now that is all good... (_track + 20) is within the bank (it starts at 0x080, plus 20 decimal = 0x094, and the bank ends at 0x0FF. The variable in track 1 however is at 0x132, which is in this next bank. This is not a problem because of the bank select instruction before each read. And here's the twist - the ASM doesn't really look like that at all. What it looks like is this: ; .line 100; main.c track[0].step[0].param1 = 0x50; MOVLW 0x50 BANKSEL (_track + 20) MOVWF (_track + 20), B ; .line 101; main.c track[1].step[0].param1 = 0x40; MOVLW 0x40 ; removed redundant BANKSEL MOVWF (_track + 178), B Notice that the second bank select is gone. This is due to the compiler optimising switch --obanksel=2 If you change it to =1, the banksel's will be left in place, and the code will work. If you don't, then all the memory reads will return 0 regardless of their value, and writes will not work at all. Now don't get me wrong, that switch is a good thing. The banksel instructions waste MCU cycles, and we want them gone... Unless we are addressing a variable which crosses the border of a memory bank. Thanks to all of you who gave me the hints I needed to spot this, and for everyone involved in MIOS studio and it's SRAM read function without which solving this would have really sucked. //////////// Note: While you're looking at that register, you may notice something like this: ; Internal registers .registers udata_ovr 0x010 r0x00 res 1 r0x01 res 1 these r0xnn variables are registers used as temporary quick ram by the compiler. There is more info in section 4.10 of the 18F452 datasheet. This coincides with TK's advice to put frequently accessed variables in the access RAM, which does not require bank selection and is therefore faster to read and write. The access RAM has memory locations 0x000 to 0x07F available. (There is another access bank which is not used in the same way, it holds the SFR's which are used to control the PIC.) The MIOS Wrapper ensures that the first 16 bytes (0x000 to 0x00F) are reserved for MIOS Functions: MIOS_VARIABLES udata 0x0000 _MIOS_BOX_CFG0 res 1 _MIOS_BOX_CFG1 res 1 _MIOS_BOX_STAT res 1 _MIOS_PARAMETER1 res 1 _MIOS_PARAMETER2 res 1 _MIOS_PARAMETER3 res 1 _TMP1 res 1 _TMP2 res 1 _TMP3 res 1 _TMP4 res 1 _TMP5 res 1 _IRQ_TMP1 res 1 _IRQ_TMP2 res 1 _IRQ_TMP3 res 1 _IRQ_TMP4 res 1 _IRQ_TMP5 res 1 The compiler will create the r0xnnn registers for use in your functions, and they are in the access ram also, starting from 0x010 as per the code at the start of this note. Hope this sheds some light on what's going on with those r0x000 things that keep showing up ;) FWIW, you can use the available access ram with the usual #pragma udata and SECTION trick, but the compiler does not seem to be aware of it's nature when using that method and still bank selects before using it. Does anyone know a way around this? Knowing all this is also very helpful in optimising our applications, because by using certain programming techniques we can optimise the ASM output by the compiler... Like, we can create structs and arrays in ways that will ensure linear access, and always use a variable when accessing them... </ramble> So, in summary: Access: Fastest, very limited, for special purposes. Is there a way to get SDCC to use it properly aside from it's own common variables? (r0x00...) Banked: Faster than indirect, only used for fixed addresses. Not suitable for extended banks - unless someone knows a way to turn off the optimizer for certain areas of code? Indirect: Slowest because of the overhead required to load the memory location, but aside from those two instructions as fast as banked access when accessing multiple sequential bytes.