Hopefully C will produce binaries that actually fits in the ROM you're aiming to use. If not, be aware that it is entirely possible to write extremely maintainable assembly language as well. The trick is to factor your code ruthlessly, even at the expense of performance (heck, C won't come close to the full performance of the CPU either). Optimize *only* those parts of the code that are speed-sensitive, and when you do, be sure to include the *equivalent* non-optimized code in the form of source comments.
When coding in assembly language, don't limit yourself to 6 letter labels. That artificial limitation was a hold-over from when it was convenient to hash symbols into 8-byte chunks of memory, two bytes held the value, and the remaining six was the label's name. On modern assemblers, this limitation doesn't apply -- use long and descriptive symbol names. You might think that symbols like getcmdproc are plenty descriptive enough. But, as you indicated above, you needed to revisit the 6502 some 20 years after your last experience with it. I'm willing to bet you, someone else will probably need to revisit your code at a later time as well. Use GetCommandProcedure instead. The next maintainer will thank you profusely for it.
Literally, code what is to be done, not how to do it. With proper design, the how will evolve naturally from the what. THis is a kind of declarative programming style, and if you've experience with Forth, you probably already have been exposed to this kind of programming. It also helps alleviate the need for comments in the source as well, thus helping to bring the product to market sooner (why write the same thing twice?).
Test prior and during the coding of the production software, not after. Every time there is a bug discovered, write a test to reproduce the bug first. Then code just enough to fix the bug. Unimplemented features are, by definition, bugs, so treat them the same. Apply this liberally and repeatedly -- over time, the result will be a product that is bug free within the scope of the given specifications. You'll notice it'll take you 3 times longer (more or less) to develop the production code this way. However, compared to traditional "code and debug" cycles, the productivity loss is a wash compared to the time spent in a debugger. Also, the more experience you gain with this methodology, the faster you become.
If you are coding by yourself, utilize top-down design, but bottom-up implementation. Make sure the foundations are bug-free before moving to the next level up. Apply logic and algebraic thinking liberally in this effort -- unit testing, as described above, plus formal methods is an unbeatable combination for writing top-quality code in a timely manner.
Run your unit tests repeatedly. Don't go home at the end of the day until 100% of the unit tests pass. If you wrote something that doesn't satisfy the unit tests prior to your day ending, scrap the code and start over again in the morning. Undoubtedly, you'll end up thinking of a different solution that is better anyway.
Write your subroutines to be as small and as simple as possible. Write them so that they cannot fail (use formal methods if it helps). Obviously, this won't always be possible, but you'll be amazed at how often it is. Handle errors as close to their source as possible.
I can't think of anything else to offer at this time. But those should be able to get the juices flowing. Whether you're coding in C or assembly language or Forth, it doesn't matter.
|