Author |
Message |
- Joined: 18 Jul 2019
- Posts: 30
|
Pointer incrementation in asm
Posted: Mon Aug 05, 2019 1:48 pm Last edited by Yuguzu on Mon Aug 05, 2019 2:07 pm; edited 1 time in total
|
Hello guys.
I'm currently looking at the code in asm generated and I see this everywere:
ld a, -2 (ix)
add a, #0x02
ld -2 (ix), a
jr NC,00155$
inc -1 (ix)
This happen when I do a basic: myPointer++;
Can someone tell why do I have:
jr NC,00155$
inc -1 (ix)
Thanks
|
|
|
- Joined: 24 Sep 2013
- Posts: 141
|
Posted: Mon Aug 05, 2019 2:02 pm
|
It looks like a 16 bit increment taking carry into account (the correct way to increment a 16bit integer)
Expected behaviour provided pointers are 16bit.
|
|
|
- Joined: 18 Jul 2019
- Posts: 30
|
Posted: Mon Aug 05, 2019 2:15 pm
|
NeonMan wrote It looks like a 16 bit increment taking carry into account (the correct way to increment a 16bit integer)
Expected behaviour provided pointers are 16bit.
I see. So the only way to bypass this is to be sure the pointer adress low byte will never go beyond 0xFF.
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14685
- Location: London
|
Posted: Mon Aug 05, 2019 6:26 pm
|
Does preincrement (++myPointer) make any difference? The code here seems to be operating on a pointer in memory via ix, which is about the slowest way possible...
|
|
|
- Joined: 18 Jul 2019
- Posts: 30
|
Posted: Mon Aug 05, 2019 11:12 pm
|
Maxim wrote Does preincrement (++myPointer) make any difference? The code here seems to be operating on a pointer in memory via ix, which is about the slowest way possible...
Same with preincrement. There are "ix" everywere :).
I guess I have no choice but to convert my c code to asm.
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14685
- Location: London
|
Posted: Mon Aug 05, 2019 11:41 pm
|
Classical C style calling conventions and stack layout really don't go well with the Z80...
|
|
|
- Joined: 24 Sep 2013
- Posts: 141
|
Posted: Tue Aug 06, 2019 12:20 pm
|
The IX increment happens because the pointer is on the stack and IX is convenient to make stack access. I'm unsure if making it `static` (move it to bss) would make a difference
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14685
- Location: London
|
Posted: Tue Aug 06, 2019 4:23 pm
|
Certainly, but in assembly we would strive never to use the stack for variables. Making it global could make it generate simpler code. If your pointer cannot cross a 256 byte boundary then it can allow much simpler code but I don’t think SDCC can deal with that.
|
|
|
- Joined: 05 Sep 2013
- Posts: 3758
- Location: Stockholm, Sweden
|
Posted: Tue Aug 06, 2019 4:40 pm
|
(if you're lucky) you'd probably get
inc hl
inc hl
using a global variable, if the function isn't complex...
|
|
|
- Joined: 18 Jul 2019
- Posts: 30
|
Posted: Tue Aug 06, 2019 6:30 pm Last edited by Yuguzu on Wed Aug 07, 2019 7:14 am; edited 1 time in total
|
sverx wrote (if you're lucky) you'd probably get
inc hl
inc hl
using a global variable, if the function isn't complex...
Yes it does. Thanks guys! You saved me lot of time.
I still got "ix" and "iy" here and there but it's lot better now. It's weird though. Sometime there is absolutely no reasons to use the stack. I think the compiler loves to use ix and iy for conditional statements:
ld iy, #_myGlobalVariable
ld a, 0 (iy)
sub a, #0x0f
jr NZ,00106$
At this point of the code there is no value stored in "hl".
|
|
|
- Site Admin
- Joined: 19 Oct 1999
- Posts: 14685
- Location: London
|
Posted: Wed Aug 07, 2019 6:20 am
|
Using the stack for storage is fine if it’s as fast as using fixed memory addresses, or if you are writing a relocatable program so you have no choice. Conversely, global are evil :) and your code will be harder to read if you use them.
In the end, the C language is not a good fit to Z80 and you have to accept the assembly is quite poor compared to hand written stuff - but accept that as the cost of not having to actually write it yourself.
|
|
|
- Joined: 14 Aug 2000
- Posts: 740
- Location: Adelaide, Australia
|
Pointer incrementation in asm
Posted: Thu Aug 08, 2019 3:12 am
|
Man, that syntax with the offset number outside of the brackets is just awful to look at.
If you cast or use a BYTE instead of an INT does the resulting code look any better? Because if, say, the pointer is pointing to your game level variable and you only have 8 level in your game, then why use 2 bytes of RAM to hold that 1 byte of info?
Quote The code here seems to be operating on a pointer in memory via ix, which is about the slowest way possible...
True that. IX and IY instructions are very slow. But when you're working with data structures they are money. If you have to increment the pointer more than twice when reading data from the structure then you're worse off using HL instead of IX or IY.
|
|
|
- Joined: 18 Jul 2019
- Posts: 30
|
Posted: Thu Aug 08, 2019 9:05 am
|
asynchronous wrote If you cast or use a BYTE instead of an INT does the resulting code look any better?
Yes it's better. Actually I found tricks to force the compiler to use available register instead of the stack. One of them is to to write this:
unsigned char* tmp = (unsigned char*)my16bitPtr;
myIncrement += myIncrement;
tmp += myIncrement
What I also so found is that the compiler doesn't organize registers use very well. Sometime it will store a value in a register where it's not very optimum. Exemple:
myGlobal16BitVar = XXXX;
myGlobal16BitVarSave = myVar;
unsigned int* myPtr = (unsigned int*)myGlobalPtr;
for(unsigned int i=XX; i>0; i--){
*myPtr++ = myVar++;
}
myGlobal16BitVar = myGlobal16BitVarSave;
In this case there is a good chance that "myGlobal16BitVarSave" will be stored in a register. And this register will not be available in the loop. Therefore the stack will be used instead in the loop.
So what I do is this. I remove this line:
myGlobal16BitVar = myGlobal16BitVarSave;
And I put this instead:
__asm
ld hl, #myGlobal16BitVarSave
ld (myGlobal16BitVar), hl
__endasm;
So now the compiler think that "myGlobal16BitVarSave" is never use and don't use a register to store it.
That's the best I found for now :)
|
|
|