BigDumbDinosaur on Sat 21 Aug 2021 wrote:
I am leaning toward the UNIX/Linux convention of loading the API index into a register and pushing parameters to the stack before making the call.
I had similar leanings. People smarter than us spent longer than us devising these conventions. However, Unix security has been an after-thought, at best. Furthermore, we've repeatedly seen that a Unix programmer's idea of minimalism is on a different scale to a 6502/65816 programmer's idea of minimalism. Despite this, I believe that where BSD calling conventions differ from Linux, BSD is faster. In the faster arrangement, parameters are on stack and register pressure is reduced. I believe it even goes as far as callee-saves which I do not like but would tolerate at module boundaries. (Within one module, callee-saves increases undesirable action-at-a-distance. However, it is preferable to have one calling convention - within modules and between modules - which places correctness above speed. Therefore, it is preferable to have caller-saves everywhere.) I otherwise like the BSD calling convention because it is portable and fairly agnostic to available registers - which may differ according to processor mode. However, we've seen that the wilful mixing of program and data has been an unending source of security flaws. Therefore, it is worthwhile to increase register pressure if it increases security. Specifically, I recommend separate program and data stacks whenever possible.
If you depart from Unix conventions entirely then do not follow Acorn's example. I am utterly repulsed by the Acorn Y:X control block pointer calling convention and I implore not repeating it with 16 bit registers and 32 bit pointers.
BigDumbDinosaur on Wed 18 Aug 2021 wrote:
The index merely has to be doubled and copied to the X-register. The front end would then execute JMP (COPTAB,X) or JSR (COPTAB,X) to select the appropriate function, where COPTAB is a 16-bit vector table.
May I suggest skipping ASL // TAX and merely placing an even value in RegX? Indeed, I have a counter-intuitive suggestion for an operating system calling convention. I suggest having a data stack pointer in RegA and the even function number in RegX. (Not the other way around.) Likewise, return codes may also be even values held in RegX. This has a certain pleasing symmetry which allows operating system and application to rapidly respond to each other's circumstances.
A stack based language on 6502/65816, such as Forth, typically maintains a data stack pointer with RegX. Whether or not Forth is the application language or operating system language, use of such a data stack would allow unrestricted parameters to be passed and returned independently of the call stack. This is ideal for I/O operations. In particular, a separate data stack is sufficient to preserve one control block across multiple system calls. Unfortunately, we also want to use RegX for JMP (abs,X) or similar. This is where the reversal is useful. I suggest a system call invocation sequence of TXA // LDX # // COP // JMP (abs,X) // TAX. At the end of each system call TXA // LDX # // STX DROPPRIV // RTI // JSR (abs,X) // TAX where DROPPRIV is an address strobe to a 74x74 or
similar functionality within a CPLD. This temporarily moves the data stack out of the way during context switches and jump table indirection but is otherwise fairly agnostic to the implementation language of the application and operating system.
It may be desirable to set a return error flag. However, it may be more convenient (and symmetrical) for an application to JSR to a dummy routine rather than have an operating system which edits the program stack at the end of every system call. Indeed, this is an example of correctness over speed.
BigDumbDinosaur on Wed 18 Aug 2021 wrote:
One last thing. As COP is an interrupt, it has a useful hardware effect. During the seventh and eight clock cycles of processing COP, the MPU's VPB (vector pull) output will go low. In a system that has privilege levels, the glue logic can react to VPB by relaxing restrictions, mimicking the user/supervisor modes of the Motorola 68K.
Genius. An unused vector becomes an operating system entry point with privilege escalation. I considered a doorbell address for privilege escalation. I didn't consider COP. COP may not be downwardly compatible but I don't think this is much of a consideration for BigDumbDinosaur. Why aren't you using 65816 in native mode already?