I’ve been bugged by this for ages, and I’ve not been able to find out anything about it… I hope one of you knows what’s going on here…
It’s about the math for calculating addresses for arrays. Here’s an example. I have nested arrays of structs that look like
track[n].step[m].something.
EVERY single time it needs to calculate an address for one of the arrays, it does the same damned pointer math like this:
n*0x9e+0*0x07+something
; ;multiply lit val:0x9e by variable r0x00 and store in r0x00
; ;Unrolled 8 X 8 multiplication
; ;FIXME: the function does not support result==WREG
; .line 100; vxevents.c track[(TRK)].step[(STP)].param1 = P1;
MOVF r0x00, W
MULLW 0x9e
MOVFF PRODL, r0x00
MOVFF PRODH, r0x03
MOVLW LOW(_track)
ADDWF r0x00, F
MOVLW HIGH(_track)
ADDWFC r0x03, F
MOVLW 0x12
ADDWF r0x00, F
BTFSC STATUS, 0
INCF r0x03, F
; ;multiply lit val:0x07 by variable r0x01 and store in r0x01
; ;Unrolled 8 X 8 multiplication
; ;FIXME: the function does not support result==WREG
MOVF r0x01, W
MULLW 0x07
MOVFF PRODL, r0x01
MOVF r0x01, W
ADDWF r0x00, F
CLRF WREG
ADDWFC r0x03, F
MOVLW 0x02
ADDWF r0x00, F
BTFSC STATUS, 0
INCF r0x03, F
MOVFF r0x00, FSR0L
MOVFF r0x03, FSR0H
MOVFF r0x02, INDF0
MOVFF PREINC1, r0x03
MOVFF PREINC1, r0x02
MOVFF PREINC1, r0x01
MOVFF PREINC1, r0x00
MOVFF PREINC1, FSR2L
RETURN
Is there some way of making the compiler be sane and have a function that can be called to do this, so I don’t have the same damned code repeated a thousand times?
It just seems strange to me that the compiler doesn’t do that already? I mean, why do the same unrolled multiply every time the array is accessed when a much simpler way is, as you demonstrated, to have one function which calculates the address, and call that…
I figured that it might be because of the need to pass 4 bytes worth of variables around creating slower code, and maybe I needed to tell it to optimise for code size (–opt-code-size) but that didn’t work I tried some of the other optimiser flags that are currently not used, but no joy there either…
I tried using a pointer to the array but no good, it just used slightly larger pointer math each time ::)… But I didn’t try forcing it to use a function of my own to calculate the pointer, I suspect that will do the trick nicely. I will have to do that soon anyway when I move the non-realtime data to SRAM, so it’s on the cards…
One tricky part is the size of the elements of the array… Obviously, SDCC calculates this on the fly but if I employ this method, then if I change the array, it’s all screwy…But again, I’ll have to work with that when it’s all in SRAM anyway.
I guess I’d like to solve these problems before I go ahead with my project, even though it won’t benefit me right now, I think it’d be nice to have solutions here for future development… Like the big arrays thing… I now see why TK breaks his seq data into small chunks of nice even sizes, and I’ll be doing the same… but I just had to know!
Assuming you’re accessing your array data sequentially, you could keep a running pointer to the current step, and just increment it by sizeof(step) to get to the next step. You’d have to do it smart though, since any extraneous variables in the track that aren’t part of the steps will need to be skipped over.
the sizeof is static.. just calculate it and put the value in the code, add a comment at the struct declaration reminding yourself to update the value.
edit: or just have a global int that gets calculated at startup