drogon on Thu 29 Apr 2021 wrote:
how you make a binary so cross platform compatible without incurring huge overhead
This divides into two cases.
In the case of an accelerator's pre-boot menu, there is absolutely no requirement to run anything inside a legacy host's address-space. It is possible, for example, to initialize Acorn 6845 using C++ and Arduino API. This has the advantage that it is possible to ignore any stray interrupts from the uninitialized system. However, there is zero opportunity to share library routines - either developed while writing the menu system or previously available to control peripherals, such as 6522. Furthermore, running the menu outside of 6502 simulation concentrates a rather bizarre corner case of dependencies including compiler dialect, I/O API and the specific pin-out of the accelerator - in addition the specifics of multiple 6502 memory maps.
In some regards, it may be more difficult to write a 6502 accelerator pre-boot menu in 6502 assembly - or the bytecode of your choice, including BCPL or BASIC. In other regards, it offers a two way flow of code re-use. In the case accelerator pre-boot menu, program size is not particularly constrained and may use memory which would ordinarily be reserved after boot. Unfortunately, in this case, strings have to be poked on a bitmap display or sent via serial. A bitmap font may be shared by all hosts if platform specific versions cannot be easily located. In the very worst case, where functionality diverges or exceeds available memory, a host may be identified and then a menu for each platform may be decompressed. Accelerators are likely to have 256KB ROM. Decompressed menu programs across all platforms may exceed 800KB.
In the case of application portability, I will be disappointed if host identification and processor feature tests add 1KB to a binary. Assuming exact matches for vectors, it is possible to fit a table of 32 entries for ABI and memory map into 256 bytes. Assuming range matches for vectors, 16 or so are possible in the same space. However, range matching vastly increases opportunity for false positives.
To make a system call, the minimum native set is GETCHR, PUTCHR, LOAD block and SAVE block. Indirection for each system call will determine wrapper function. These may include GETCHR on Acorn, GETCHR on Communicator, GETCHR on Ruby, GETCHR on Planck, GETCHR on PET, GETCHR on VIC20 and GETCHR on Apple II. Your binary may support no more than one platform and each wrapper is likely to be less than 20 bytes. You do not have to support all of Acorn's API on Commodore - unless you want to. You may also want API feature tests. "Does this platform have a printer output?" may indirect to an arbitrary test. In the trivial case, CLC // RTS indicates no. The application may then hide print options when running on a platform which does not support printing. Effectively, functionality is selectively culled on each platform. Only the useful subset of available functionality is presented. This leads to the curious case where all platforms may support facets of an application but no platform supports it in full.
Applications are not linked with screen scrolling, keyboard scanning, serial drivers, printer drivers or sound generation unless such functionality is essential and commonly absent from target platforms. Unfortunately, applications may be statically linked with POSIX cruft, such as printf.
drogon on Thu 29 Apr 2021 wrote:
I'm in the process of almost abandoning the standard Acorn MOS vectors at $FF80 upwards and moving the whole lot down to $FDxx... ($FExx is hardware IO)
Commodore, Acorn and W65C265 use the same memory locations for vectors. Applying
lighthouse protocol, one of these is preferentially unmoved. Personally, I'd abandon page $FF and leave all of it for microcontroller hardware vectors - or anyone brave enough to use it for I/O. For example, jfoucher's Planck uses approximately half of page $FF for I/O. Other CPLD systems do similar. However, I would move an Acorn ABI to page $FB. It feels *wrong* telling an Acorn 6502 application to jump via page $FC, $FD or $FE (FRED, JIM or SHEILA). Likewise for a Commodore ABI in the same address-space, although less so. Therefore, to minimize unease, I suggest:-
- Hardware indirection vectors working backward from the end of page $FF.
- Re-located Commodore jump vectors working backward from the end of page $FD.
- Re-located Acorn indirection vectors working backward from the end of page $FB.
I believe this would be compatible with W65C134, W65C265, Planck, Ruby, Steckschwein and other systems.
drogon on Thu 29 Apr 2021 wrote:
I have a workaround for BBC Basic which is the only "classic" Acorn software I care for right now
Do you transparently patch known binaries? I've suggested similar for Sargon II Chess. I believe that faster processors may look two or three moves further ahead without screwing the weighted score system.
In general, we have an interplay where application may identify operating system while operating system may identify application. The problem is that useful operating systems and applications pre-date this scheme. An operating system which is aware of legacy applications may patch binaries. Likewise, an application may adapt to a known set of legacy operating systems. The interesting part occurs when an aware application runs on an aware operating system. In this case, a superset of legacy ABIs may be invoked.
drogon on Thu 29 Apr 2021 wrote:
So how to positively identify a Ruby board...
We cannot use $C000 because that is the address of a 6522 on some systems. Actually, we cannot use page $00, page $02-03, page $80-$DF or page $FC-$FF. I may have missed cases but I believe that part of page $01 is available. Immediately prior to executing an application, place six bytes of your choice at $0100-$0105 followed by zero, zero. The six bytes should not look like a string, return address, vectors or fresh memory and will be used on all participating platforms. Something like $A4, $4F, $01, $FE would be a suitable start. Ruby will be ABI zero.