Re: Compact code
My first full-time employment included a "side-line" in writing software for the BBC Microcomputer... another 65C02 based machine. The Beeb used memory-addressed peripherals [no pesky device drivers for you, me boy] and page-swapping to enable it to support more addressable storage than the default 64kb. The lower half of the address space was RAM, the upper half was ROM. Acorn's Operating System sat in the "top half" of the ROM address space and the lower half - i.e. memory from 32768-49151 was reserved for "paged ROMs" ...
The OS itself had a design convention that identified "system commands" through the use of an asterisk to prefix the command and anything submitted to the command line prefixed with an asterisk would first be offered to the OS; then, if it was not recognized, the OS would "page" through any installed ROMs, swapping them in to the available address space and offering them the unknown command. If it tried all available ROM's and didn't get a bite, it would issue an "unknown command" response.
So far, so good.
I was asked by my boss to take some code [written in BBC BASIC] that provided ISAM functionality to the Beeb's flat data files [basically, giving them an Indexed-Sequential Access Methodology index-retrieval system] and convert the code in to 6502 assembler so that we could shunt all the index-handling logic in to ROM to save RAM for actual "business logic". A couple of different "6502 Assembly Language Programming" books later and I had working code - able to support 3-tier indices with up to 20 keys per block [blocks aligned in size with disk sectors for IO efficiency]. Translation: it could handle 4000 records assuming 50% index density - theoretically up to 8000 records, but that would be a bit optimistic.
The catch? My code compiled down to about 10kb.
At which point my boss announced that he'd already been out and purchased a stack of 8kb EEPROMs and I'd just have to rewrite my assembler to make it more compact.
Took me about a month - and let me tell you, that remains one of the toughest programming challenges I've ever faced. The first half - getting the code from about 10kb down to about 9kb was *relatively* straightforward... I cheated a little bit as I had a couple of unfolded loops that I'd written to perform "block copy" operations when performing a "block split" of one of my index blocks... It slowed down the update operation - but I figured that since the machine was physically writing to disk and since the disk operation would be a limiting factor, I could likely get away with it, so I just folded the code back up as a loop and saved a bunch of memory.
But getting those last few bytes, down from about 8300 or 8400 bytes to something that would fit in an 8kb EEPROM... Man, that was *hard*... and to get there I ended up using solutions I find "ugly" to this day... For example, the 6502 uses different types of code branching: JMP ["Jump to memory location and start executing"] and JSR - Jump to SubRoutine - ["push your memory location on to the heap, jump to a memory location and start executing... then, when you encounter a "Return" opcode, pull the address of the heap and go back there before executing..."]. You end up writing subroutines with multiple entry points, then a common exit/return, because doing that will save you a *single byte* of RAM, since you now only need one "return" opcode.
Or you make a "declaration" that your code won't run on a BBC Micro equipped with an IEEE488 interface [used with oscilloscopes, voltmeters, logic analyzers and the like], because that would free up a tiny amount of RAM in Page Zero. And Page Zero RAM was invaluable because the hex structure for:-
LDA &40 [Load the Accumulator with the contents of memory address hex 40, which is *in* Page Zero]
took two bytes of RAM to express, while the hex structure for
LDA &1900 [Load the Accumulator with the contents of memory address hex 1900, which is not in Page Zero]
took *three bytes* of RAM to express...
I found that by rewriting my assembler to use Page Zero addresses saved me *just* enough to get my code to compile down to 8kb.
At the time I hated it... I had no experience of assembler and I really struggled. There was no "internet" to turn to and no "user group" to ask... After the first couple of weeks I convinced myself my boss would fire me in disgust, but he seemed genuinely surprised that I'd managed it.
We can look back on a 6502 today - 2MHz clock, three 8-bit registers (Accumulator, X and Y registers) and then 8 one-bit status flags (e.g. the Carry Flag) - and think of it as crude and primitive...
But learning what was needed to wring the last drop of performance out of that antique piece of silicon gave me skills that have paid me back over decades.