laoo Posted April 23, 2020 Share Posted April 23, 2020 Just pointing out that @ilmenit wrote an article about cc65 optimizations in Atari 8-bit subforum. I think it could be of interest regarding Lynx development 3 1 Quote Link to comment Share on other sites More sharing options...
+karri Posted April 23, 2020 Share Posted April 23, 2020 1 hour ago, laoo said: Just pointing out that @ilmenit wrote an article about cc65 optimizations in Atari 8-bit subforum. I think it could be of interest regarding Lynx development Nice article. Many of these details are the ones that I have found out the hard way. Usually working for hours to find a byte I can get rid of. Using global variables may be bad coding technique but it helps keeping the code small. The biggest savings that I have found is to always maximize the segment size. Using small segments and flipping them in and out reduces available RAM. It is better to duplicate graphics in the ROM as there is plenty of space in ROM compared to RAM. Again bad coding but it helps you get the extra mile. 1 Quote Link to comment Share on other sites More sharing options...
drludos Posted April 23, 2020 Share Posted April 23, 2020 Thanks a lot for sharing, I've discovered a lot of stuffs I didn't knew, so I hope my next Lynx game will run faster! ? Quote Link to comment Share on other sites More sharing options...
LordKraken Posted April 24, 2020 Share Posted April 24, 2020 (edited) Something one can deduce from the "struct of array" optimization is to not use struct for single entity. For instance, if you have: Struct SGameManager { int timer; uchar state; bool isPaused; etc... }; SGameManager myGameManager; Since you're very likely going to have one and only one game manager, then you better define it like that: int myGameManager_timer; uchar myGameManager_state; bool myGameManager_isPaused; it's faster and reduce your code significantly. Edited April 24, 2020 by LordKraken 2 Quote Link to comment Share on other sites More sharing options...
ilmenit Posted April 24, 2020 Share Posted April 24, 2020 (edited) 6 hours ago, LordKraken said: Something one can deduce from the "struct of array" optimization is to not use struct for single entity. For instance, if you have: Struct SGameManager { int timer; uchar state; bool isPaused; etc... }; SGameManager myGameManager; Since you're very likely going to have one and only one game manager, then you better define it like that: int myGameManager_timer; uchar myGameManager_state; bool myGameManager_isPaused; it's faster and reduce your code significantly. It's not necessary ? If you have the structure like above as a static in global space, then CC65 generates code equal to accessing separate variables as below. I'd recommend to keep the SGameManager for code readability. Edited April 24, 2020 by ilmenit Quote Link to comment Share on other sites More sharing options...
+karri Posted April 24, 2020 Share Posted April 24, 2020 How the structs are handled are very compiler dependent. @LordKraken is still using the old "newcc65" compiler and sucks big time with structs. Quote Link to comment Share on other sites More sharing options...
LordKraken Posted April 24, 2020 Share Posted April 24, 2020 Yep exactly that Nice that cc65 do this optimization.... with newcc65 you have to accept that there is no obvious optimization ohhohh and no function pointers ? one day I will switch Quote Link to comment Share on other sites More sharing options...
ilmenit Posted April 25, 2020 Share Posted April 25, 2020 I found out that compiler does this optimizations looking at e.g. cc65\include\_atarios.h where nested structs and unions are used and finding out that compiler is generating very efficient code for them. Which version of cc65 does not do such optimizations? I could add to the article min. version. Quote Link to comment Share on other sites More sharing options...
LordKraken Posted April 25, 2020 Share Posted April 25, 2020 It's newcc65 and, as far as I know, it has very little to do with cc65, (maybe it's a very old fork?), but @sage or @42bs probably know more, if not all, about that It has a few cool stuff though, like inline asm. Quote Link to comment Share on other sites More sharing options...
sage Posted April 25, 2020 Share Posted April 25, 2020 i am not sure if this was already called "fork" 20 years ago... Quote Link to comment Share on other sites More sharing options...
ilmenit Posted April 25, 2020 Share Posted April 25, 2020 4 hours ago, LordKraken said: It's newcc65 and, as far as I know, it has very little to do with cc65, (maybe it's a very old fork?), but @sage or @42bs probably know more, if not all, about that It has a few cool stuff though, like inline asm. https://cc65.github.io/doc/cc65.html#s9 Quote Link to comment Share on other sites More sharing options...
LordKraken Posted April 25, 2020 Share Posted April 25, 2020 (edited) Ohh but that way not as nice as in newcc65 if you ask me Not that i have a lot of asm in my code anyway ^^ Edited April 25, 2020 by LordKraken 1 Quote Link to comment Share on other sites More sharing options...
42bs Posted April 26, 2020 Share Posted April 26, 2020 On 4/25/2020 at 10:16 AM, LordKraken said: It's newcc65 and, as far as I know, it has very little to do with cc65, (maybe it's a very old fork?), but @sage or @42bs probably know more, if not all, about that It has a few cool stuff though, like inline asm. Acutally, I have no idea where the current cc65 differs from my version. See http://www.monlynx.de/lynx/cc65notes.html for more info about "newcc65" Quote Link to comment Share on other sites More sharing options...
42bs Posted April 26, 2020 Share Posted April 26, 2020 I see, the current cc65's inline assembly is inspired from the gcc. But then who uses C on 65C02. Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted April 30, 2020 Share Posted April 30, 2020 (edited) Very nice article @ilmenit! That should be very helpful for people who are programming in cc65. I wasn't sure if you mentioned __fastcall__, but that may be a default behaviour of cc65 now. I find that if you are used to the way that cc65 does things, you learn to program in the "cc65" way. Generating assembly listings and map files when you compile is mandatory, and you should get in the habit of looking at them to figure out what cc65 is doing both from a code generation point of view, but also memory usage (in larger projects). In larger projects I don't see how you can really use static locals (you'll run out of memory), but maybe there would be some cases where that might work. When I was porting Moria to the Atari 8-bit, mostly I started optimizing in this order: 1. Making sure all the data types were the smallest possible (unsigned char instead of int). 2. Using the register keyword to have some local variables in zeropage (cc65 only has 6 zeropage "register" variables), and there is a little overhead to save and restore the contents. Usually loop variables and pointers are good candidates. 3. Any large local variables, were changed into globals. Some of those could be shared (if very careful), like buffer string space. 4. Moved heavily used globals to zeropage, both to optimize memory and speed. 5. Lookup tables, for speed mainly. 6. With Moria, I needed space and would often be trying to eke out bytes to get things to fix in cartridge banks. Including making sure that read-only data was stored in the cartridge bank and not in the main memory RODATA bank. Memory management is a huge thing with a small 64k machine. Edited April 30, 2020 by Shawn Jefferson Quote Link to comment Share on other sites More sharing options...
ilmenit Posted May 1, 2020 Share Posted May 1, 2020 7 hours ago, Shawn Jefferson said: In larger projects I don't see how you can really use static locals (you'll run out of memory), but maybe there would be some cases where that might work. I think it may depend on how many variables you are using in functions, but additional stack operations and accesses in the code make the code size so big that at least for me it was less memory consuming to use static-locals. 7 hours ago, Shawn Jefferson said: 2. Using the register keyword to have some local variables in zeropage (cc65 only has 6 zeropage "register" variables), and there is a little overhead to save and restore the contents. Usually loop variables and pointers are good candidates. while there are only 6 "register" variables, you can define a lot of them just putting variables into Zero Page segment. All your points are great hints! How is the Moria project going? I think it may really challenging to port big code into banked memory. I wish it could be somehow automated with CC65. I'm a big fan of roguelikes myself and even did a few ? The biggest but never finished was Xenocide, which is still available on http://xeno.chaosforge.org/ and reviewed e.g. here https://weyland.fandom.com/wiki/Xenocide:_The_Roguelike Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted May 12, 2020 Share Posted May 12, 2020 On 4/30/2020 at 11:23 PM, ilmenit said: I think it may depend on how many variables you are using in functions, but additional stack operations and accesses in the code make the code size so big that at least for me it was less memory consuming to use static-locals. Your code also becomes non-reentrant, which means that you have to be very careful with leaf functions. I suppose that would have to be a somewhat complex program though (??), but still, that may be a nasty surprise if you aren't ready for it. On the Moria port, I had to be careful of that when I was moving local variables from the stack into zeropage. I believe I did find a few examples where I couldn't move the variables easily off the stack. On 4/30/2020 at 11:23 PM, ilmenit said: while there are only 6 "register" variables, you can define a lot of them just putting variables into Zero Page segment. Using the register keyword avoids the problem I mentioned above, but there are only 6 bytes available (I shouldn't have said 6 register variables, since an int will use up two byes. And the code to push and pull them off the stack that allows your functions to be reentrant. A good compromise solution for some extra speed without changing the program much. On 4/30/2020 at 11:23 PM, ilmenit said: All your points are great hints! I thought posting a reply would be good for anyone who's looking at CC65 for programming, and add to the points you made in your document. I didn't think you'd needed the advice, you've been using the suite for a long time now! On 4/30/2020 at 11:23 PM, ilmenit said: How is the Moria project going? I think it may really challenging to port big code into banked memory. I wish it could be somehow automated with CC65. I've been away from it for a while now, but I do have a more recent version I should upload that has some bugfixes and more polishing. There's still a bit left to do, to truly call it done. On 4/30/2020 at 11:23 PM, ilmenit said: I'm a big fan of roguelikes myself and even did a few ? The biggest but never finished was Xenocide, which is still available on http://xeno.chaosforge.org/ and reviewed e.g. here https://weyland.fandom.com/wiki/Xenocide:_The_Roguelike They are an interesting game genre, and I played them a lot through high school and at jobs where I had only had a monochrome PC at work. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.