Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MOS should support an extension system #91

Open
stevesims opened this issue Sep 7, 2023 · 3 comments
Open

MOS should support an extension system #91

stevesims opened this issue Sep 7, 2023 · 3 comments
Labels
idea A good idea that may be turned into an enhancement

Comments

@stevesims
Copy link
Contributor

MOS currently offers no mechanism to add new API calls, and the only mechanism to add a star command is via executables stored on disc that will be automatically executed if an unrecognised command is typed in.

To add in a new API call, or a resident star command, requires changing the MOS source code and re-building it.

We should provide mechanisms to add in new API calls, and star commands.

Acorn's MOS in contrast allowed for extensions via ROM and sideways RAM. Unrecognised calls/commands/interrupts etc would be passed on to any resident ROMS in turn to see if they chose to handle the call. This is done via OSBYTE 143

Implementing a similar system in the Agon MOS will allow us to build OS extensions that can increase the capabilities of the system.

One example of an extension module would be for joystick interface support. There are already several different solutions to physically adding joysticks to the Agon (there are a few different hardware add-ons, and the Agon Console8 has interfaces built in). If we have a module system then we can define a single standard API to get joystick information - each different interface could provide a module that implements the standard API. Software written to use that standard API and work with all joystick interfaces.

Without such a module system a developer wishing to add joystick support to a game would need to add custom code for every joystick interface they wish to support. New joystick interfaces would be unlikely to be compatible with older games unless the interface happens to be designed to work identically to an existing interface.

@breakintoprogram
Copy link
Owner

This is made possible by the BBC Micro being able to page a ROM into a 16K block from address &8000; code can therefore be assembled to run at that address.

In ADL mode, the eZ80 code is compiled / assembled to the address where the code is to execute. Relocating Z80 code at runtime is not trivial.

In Z80 mode, the Z80 code runs within a 64K segment, and the segment can be relocated, but must fall on a 64K boundary. This is achieved by setting the eZ80 MB register, which effectively forms the most significant byte of the address space (bits 16-23), thus where that 64K sits in memory. So each module would occupy 64K & have to be written in Z80 mode. This precludes C, which requires ADL mode.

MOS gets around this by compiling any external MOS command at a fixed address, and this is a reserved block at the top of memory.

@stevesims
Copy link
Contributor Author

hey @breakintoprogram thanks for your insights. (sorry to keep you hanging - I'd intended to respond sooner - took me a while to get over a cold...)

you are of course entirely correct as to how this was practical on a Beeb. the differences and parallels are very interesting.

it's a shame that the eZ80 works in 64kb segments. the restriction of using only z80 code in a segment (and no C) feels like something that could be lived with, but the segment size is really too large to dedicate to a single module. if only there were smaller segments, like 16kb, then this approach would probably be practical, but it is not to be.

this leaves the idea of relocating (e)Z80 code. as you say, doing that at run-time is not trivial. I think though that there may be ways to make it practical.

scanning thru a binary and working out new addresses for absolute jumps, assuming you know the original execution address, and then changing them to be based off a new base address, is not really that hard. if only things were that simple. 😁

as I see it, the main difficulty is jump tables. these are a much harder problem. it may be just about possible to work out code that's doing a jump table, but it's virtually impossible to work out where within a binary file a table begins and ends.

but I have an idea...

I did a great deal of my "learn z80" work by reading the Ms. Pac-Man code. in that code, RST 20 is a jump table handler. this means is that the pacman code only has one way of doing jump tables, so anywhere a jump table is needed there's an RST 20 instruction followed by a list of jump addresses.

what if we had a similar "jump table handler" RST in MOS?

the exact implementation used in pacman is fairly straightforward, but would not be exactly suitable for our needs - we'd probably want to add in a "length" at the beginning of the table so we know how long it is.

having such a RST call means that we could scan thru a binary to find such an instruction and therefore to find jump tables, and then be able to adjust the addresses in that table.

the remaining difficulty in relocating a module would be areas of non-code in the binary. when relocating a module there's essentially two ways to go about things - either non-code areas would need to be "marked" in some way so the relocation routine could skip over them, or the relocation routine could "walk the code" to find all the potential executable code paths. obviously there are issues around this in terms of routines that use addresses of data that need some more thought than I'm giving here in this comment. perhaps there's potential for another RST call for "get address of data block" (needs more thought).

another potential issue with relocatable ez80 code is self-modifying code, but, well, let's just ignore that. the rules for relocatable modules in MOS should include "no self-modifying code" - essentially the module is a ROM.

these ideas probably mean that relocatable MOS modules would be restricted to assembler (as who knows what a C compiler will produce) but that feels like it could be a reasonable compromise.

@breakintoprogram breakintoprogram added idea A good idea that may be turned into an enhancement and removed enhancement New feature or request labels Sep 27, 2023
@S0urceror
Copy link

We could introduce a new style of binary that starts with a header telling that it's a relocatable module. Then incorporate a relative address table with relative addresses need updating in the binary after loading.

Example from MSXDOS in Z80 mode. Something similar could be made for ADL mode.

START:
        LD HL, _RAT
        LD BC, SOURCE
        LD DE, 4000h
        CALL RELOCATE
        RET

_RAT:  DEFW    R000C-SOURCE
        DEFW    R001E+1-SOURCE
        DEFW    R002F-SOURCE
        DEFW    0FFFFH

SOURCE:  PUSH    IX
        PUSH    IY
        PUSH    HL
        PUSH    DE
        PUSH    BC
        PUSH    AF
        EXX
        EX      AF,AF'
        PUSH    AF
        PUSH    HL
R000C:  LD      HL,(D635E+1)
        LD      A,L
        OR      H
        POP     HL
        LD      IX,KEYINT
        LD      IY,(EXPTBL+0-1)
        JR      NZ,J6375
        POP     AF
R001E:  LD      (D635E+1),SP
R0021:  LD      SP,0
        CALL    CALSLT
        DI
D635E:  LD      SP,0
        PUSH    HL
        LD      HL,0
R002F:  LD      (D635E+1),HL
        POP     HL
J6369:  EX      AF,AF'
        EXX
        POP     AF
        POP     BC
        POP     DE
A636E:  POP     HL
        POP     IY
        POP     IX
        EI
        RET

RELOCATE:  PUSH    DE                      ; DE = destination, HL = reloctable, BC = source
        EX      DE,HL
        AND     A
        SBC     HL,BC                   ; delta dest - source
        PUSH    HL
        POP     IX                      ; delta in IX
        EX      DE,HL
        POP     DE
J6310:  LD      C,(HL)                  ; DE = destination, HL = ptr start reloctable, BC = source
        INC     HL
        LD      B,(HL)                  ; BC holds contents reloctable entry
        INC     HL
        LD      A,C
        AND     B
        INC     A
        RET     Z                       ; ffffh to signal end of relocation table
        PUSH    DE                      ; DE = destination, HL = ptr to next entry reloctable, BC reloctable entry                
        EX      DE,HL   
        ADD     HL,BC                   ; destination + reloctable entry
        INC     HL                      ; +1
        LD      C,(HL)
        INC     HL
        LD      B,(HL)                  ; BC = current contents of destination memory
        PUSH    HL                      
        PUSH    IX
        POP     HL                      ; HL = delta
        ADD     HL,BC                   ; calculate new value
        LD      C,L
        LD      B,H                     ; BC is new value
        POP     HL                      ; HL = ptr to next entry reloctable
        LD      (HL),B
        DEC     HL
        LD      (HL),C                  ; update contents of destination memory with new value
        EX      DE,HL
        POP     DE
        JR      J6310                   ; next entry

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
idea A good idea that may be turned into an enhancement
Projects
Status: On Hold
Development

No branches or pull requests

3 participants