10 hours ago, kktos said:
? It was me saying oh no, not again ? But I'm smiling while writing it down. No worries ?
So you asked a very good question: why ? Good, let's think about it.
Honestly, Commodore knew what they were doing with the KERNAL jump table, and while I strongly disagree with several of their design principles, this is one that makes sense.
Quote
1- (Weak argument) you'll have a 3 bytes * n addresses, bigger than a 2 bytes * n.
The 6502 does not support an indirect JSR, so using a vector table means writing additional code to set up the system call in the first place. The best use for vector tables is in mutable entry points. For example, we can modify the behavior of BASIC at runtime by changing the vector that reads the tokens:
Quote
-2- (Weak argument) you'll have to remember a lot of addresses
If there are n system functions to call, you need n function numbers. It doesn't matter of those take the form JMP n or LDX n; JSR SysCall. You still have the same number of addresses to memorize; you're just plugging those addresses into a different place in your code.
Quote
- vectors table
-1- you'll have a single point of entry
-2- your API could be very easily consistent and coherent. You can have a stub code dealing with the parms and then calling the internal function. you're making a toolbox rather than a bag of tricks.
-3- for the dev, once he gets how to deal with your entrypoint API, job's done. Pretty easy to use.
-4- (Weak argument) pretty easy to add, change or remove a function as all calls go thru the stub.
A single point of entry has no inherent value when a program has multiple routines that can be invoked.
This does nothing to promote consistency. With only 3 registers, your program still needs a way to pass parameters. The JSR address has nothing to do with the parameter addresses.
If developers need to learn to "deal with your entry point API" on top of your individual functions, you did something wrong.
Irrelevant. A dispatch routine still needs a lookup table for subroutine addresses, and the developer still needs to be informed of new and deprecated routines.
A single point of entry is a liability, as you're going to waste at least 20 cycles just loading the jump address, plus additional cycles marshaling parameters. And let's not forget that using up a parameter for your function name means losing that space for passing parameters to your functions. This increases complexity, which either decreases performance or decreases reliability.
Finally, there's nothing inherently coherent or consistent about a single entry point; the consistency of your API depends entirely on... designing a consistent API. In fact, the worst APIs I have seen are the ones where someone tried to shoehorn a bunch of functions into a single entry point, rather than creating a separate function for each procedure.
Consider the following c style function calls. Which is more readable?
DispatchCommand(LoadFileFunction,"filename");
or just
Load("filename");
The second is always going to be easier to read and easier to invoke. Likewise, when I'm looking at Commodore assembly code, and I see JSR $FFD2, I know that's CHROUT. I don't have to backtrack the code to look for an LDX #2, because JSR $FFD2 is an explicit call to the CHROUT function. It will always mean exactly that, no matter what data is in parameter memory or in the registers.