Enterprise Forever

:UK => Programming => BASIC => Topic started by: gflorez on 2014.August.14. 01:06:14

Title: Easy relocatable code in basic
Post by: gflorez on 2014.August.14. 01:06:14
I'm interested in relocatable code, programs that can work independently of the configuration of the EP.

The problem is when you want to make it easily in Basic. RESTORE or ALLOCATE can give you spare memory for your code, but the direction can be different if you have been running another program before or have made immediately a reset.

But if you want the code to work on every EP you must think about relocatable modules.

No, I talk about tiny code with some jumps or calls inside. The Z80 wasn't engineered with relocatable code in mind( except the useful JP(HL) widely used in the EXOS, or the relative jumps, too shorts to be useful).

Then I've though about an easy way to do the trick:

  100 ALLOCATE 20
  110 CODE ORIGEN=HEX$("00,00,00,01,00,02,00,03,00,04,00,05,00,06,00,07,00,08,00,09")
  120 LET CODH=INT(ORIGEN/255)
  130 LET CODL=REM(ORIGEN,255)
  140 FOR A=0 TO 9
  150   READ B,C
  160   LET DIREC=(B*255)+C+ORIGEN
  170   LET H=PEEK(DIREC)
  180   LET L=PEEK(DIREC+1)
  190   LET L=L+CODL
  200   LET H=H+CODH+INT(L/255)
  210   LET L=REM(L,255)
  215   PRINT DIREC,PEEK(DIREC),PEEK(DIREC+1)
  220   POKE DIREC,H
  230   POKE (DIREC+1),L
  240 NEXT A
  250 DATA 0,0,0,2,0,4,0,6,0,8,0,10,0,12,0,14,0,16,0,18
  255 PRINT
  260 FOR A=0 TO 9
  270   PRINT ORIGEN+(A*2),PEEK(ORIGEN+(A*2)),PEEK(ORIGEN+(A*2)+1)
  280 NEXT A

In lines 100-110 we put a test code in the Basic variable memory as usual.
In 120-130 we extract the H and L bytes of the new ORG direction.

Then, in the 140-240 loop we read from DATA in line 250 the absolute directions(ORG=0) we need to relocate .

Then the  content of the memory is compared before and after.
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2014.August.14. 14:45:37
The 255 values are wrong, use 256!
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2014.August.14. 16:18:33
Oh sorry. I'm on holidays without the real thing... no excuses.....Error is my second name....
 
The program fixed:

  100 ALLOCATE 20
  110 CODE ORIGEN=HEX$("00,00,00,01,00,02,00,03,00,04,00,05,00,06,00,07,00,08,00,09")
  120 LET CODH=INT(ORIGEN/256)
  130 LET CODL=REM(ORIGEN,256)
  140 FOR A=0 TO 9
  150   READ B,C
  160   LET DIREC=(B*256)+C+ORIGEN
  170   LET H=PEEK(DIREC)
  180   LET L=PEEK(DIREC+1)
  190   LET L=L+CODL
  200   LET H=H+CODH+INT(L/256)
  210   LET L=REM(L,256)
  215   PRINT DIREC,PEEK(DIREC),PEEK(DIREC+1)
  220   POKE DIREC,H
  230   POKE (DIREC+1),L
  240 NEXT A
  250 DATA 0,0,0,2,0,4,0,6,0,8,0,10,0,12,0,14,0,16,0,18
  255 PRINT
  260 FOR A=0 TO 9
  270   PRINT ORIGEN+(A*2),PEEK(ORIGEN+(A*2)),PEEK(ORIGEN+(A*2)+1)
  280 NEXT A
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2014.August.14. 16:28:20
Alternate idea: do the realocation in machine code.
Write the routine in Turbo Asmon, it is can compile to BASIC program (With Allocate and CODE strings).
  ORG 0
  JR MAIN
  PUSH HL
  POP BC
  LD HL,(CALL1+1)
  ADD HL,BC
  LD (CALL1+1),HL
  LD HL,(CALL2+1)
  ADD HL,BC
  LD (CALL2+1),HL
  ...
  RET

MAIN
  ...
CALL1 CALL SUB1
  ...
CALL2 CALL SUB2
 ...

In the BASIC add a variable for the start for example MCODE
Befor it is used CALL USR(MCODE+2,MCODE) which are do the relocation.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2014.August.14. 17:01:42
Thanks Zozo, really your nethod is easy to implement. Only remember, I usually code by hand.....but can do bigger and better things if I begin using an assembler....

Is Turbo Asmon the best?
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2014.August.14. 17:07:42
Quote from: gflorez
Is Turbo Asmon the best?
Yes, for compile code to BASIC.
For native machine code programs the HEASS are the best, it is can use all memory then you can handle very large sources (with memory expansion). And it is very fast, for example EXDOS 1.3 compile only 43 seconds on 4MHz machine! It is about 300k source in plain text format.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2014.August.14. 17:22:12
Ok. And, about the English manual, is it important?
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2014.August.14. 20:23:57
Quote from: gflorez
Ok. And, about the English manual, is it important?
English manual for which program? :oops:
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2014.August.15. 14:44:14
The two if  possible...HEASS and T-ASMON.... Or, can I begin without manuals?
Title: Re: Easy relocatable code in basic
Post by: endi on 2014.August.15. 17:05:34
try EP Plus. you can write asm into basic lines!
http://ep128.hu/Ep_Konyv/Ep_Plus.htm
Title: Re: Easy relocatable code in basic
Post by: BruceTanner on 2014.August.15. 17:07:33
For more serious amounts of machine code, EXOS supports a relocatable file format, so you can do an EXOS call to load a relocatable user program or device driver into an arbitrary block of memory.

zozo: do you know if anyone actually ever used this in practice? It would mean they would have to have a way of producing the bit stream file format. I remember at IS we used to assemble relocatable modules twice, each time with a different ORG (probably 0 and 100h but I can't actually remember) and then we wrote a little utility program that would compare the two files and thus know which bits need to be relocatable, and output the appropriate bit stream file format.
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2014.August.17. 11:00:45
Quote from: BruceTanner
zozo: do you know if anyone actually ever used this in practice?
Yes, BASIC command set expansions are use this format, and some EXOS system extensions are also.
But no too popular used because lack of support in assemblers. Not documented but I found the way in Asmon how possible creat relocatable code. Not too comfortable, but working :-)
At all 16 bit expressions need to set it is relocatable code or absolut value. For example:
Code: ZiLOG Z80 Assembler
  1.                 PUSH DE
  2.                 POP IY
  3.                 .CSEG
  4.                 CALL CSATSZAM
  5.                 .ASEG
  6.                 LD (7FFBH),A
  7.                 INC DE
  8.                 DEC B
  9.                 .CSEG
  10.                 JP M,ALAPOTCSINAL



Quote
It would mean they would have to have a way of producing the bit stream file format. I remember at IS we used to assemble relocatable modules twice, each time with a different ORG (probably 0 and 100h but I can't actually remember) and then we wrote a little utility program that would compare the two files and thus know which bits need to be relocatable, and output the appropriate bit stream file format.
Very interesting idea! Unfortunatelly this utility not published :-(
Now I thinking write similar one :-)
Title: Re: Easy relocatable code in basic
Post by: lgb on 2014.August.17. 13:39:23
Quote
Very interesting idea! Unfortunatelly this utility not published :-(
Now I thinking write similar one :-)

I used the same trick with my very elementary "original" CP/M to EP128 porting: I had the disassembled CP/M BDOS from the Net, I assembled it with ORG 0 and ORG 100h. I wrote a simple python script (running on PC): where the byte values were different I stored the positions inside a table and I used ORG 0 version, so I simply had to add the offset. Since I was about relocating to positions on 256 byte boundaries, I only needed to deal with the high bytes (of course the theory works with even byte granulities, but it needs two tables, as some ops may use only low an and high bytes, and such).
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2014.August.18. 01:06:44
Its amazing, I`m not the only one thinking about these "odd" things!

I remember that the Interlace mode program is in fact another relocatable module. Loading not needing  permisions, implantig their code in System  like real virus do....
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.25. 17:36:39
I want to convert a MSX machine code application to Enterprise, it is SETalk, the voice synth.

On MSX it is loaded by a Basic program at a fixed address, but now I want it to work on every Enterprise.

I have been thinking about real relocatable code, not relocatable conversion like it is explained at the beginning on this thread.

---

The real problem I found about doing relocatable code with the Z80 is the impossibility to read the PC register to know the address of the instruction the processor is actually executing.

CALL and JP are the worst instructions to convert to relocatable, but we at least have JP (HL), that eases a lot the conversion.

Also, IS-Basic lets to pass a 16 bit number to the HL register pair on a machine code program created with the command CODE ROUTINE=HEX$("XX","XX", etc), and then the routine called with CALL USR(ROUTINE,ROUTINE)(Thanks Zozo for the tip).

Now we have the start address passed to HL. The routine has been assembled with a ORG 0000h.

Code: [Select]
SETALK:         PUSH    AF
                PUSH    BC
                PUSH    DE
                PUSH    HL


                CALL    PROG

                POP     HL
                POP     DE
                POP     BC
                POP     AF
                               

I have though that something like this will serve me to do a call:

Code: [Select]
SETALK:         PUSH    AF
                PUSH    BC
                PUSH    DE
                PUSH    HL          ; is good to store another copy of the start address just in case

                LD      DE, RET1 ; we need the relative address of the return
                PUSH    HL
                ADD      HL, DE
                EXX      DE, HL
                POP      HL
                PUSH    DE          ; Now we have the absolute return address on the stack
                PUSH    HL
                LD      DE,PROG
                ADD      HL,DE
                POP      DE         
                JP      (HL)        ; We still have the start address on DE, but we can
                                    ; pass more data by the stack if we remember to POP it
                                    ; inside the simulated call
                ;CALL    PROG

ret1:           POP     HL
                POP     DE
                POP     BC
                POP     AF
                               


But surely you know an easier way....
Title: Re: Easy relocatable code in basic
Post by: IstvanV on 2018.April.25. 18:21:14
It is not the most elegant solution, but if there is any fixed address that is safe to temporarily overwrite, then a JP (HL) (E9h byte) can be stored there and called so that it effectively becomes CALL (HL). Or even something like CALL (IX + DE) with a few more bytes. Possible places to store the JP (HL) at include the beginning of page 0, and usually unused parts of the EXOS stack around AC00h.
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2018.April.25. 20:05:43
EXOS have a support for a relocatable modules, header 02h
1) little code needed which is using EXOS 30 for load the remaining code from relocatable module
2) IS-BASIC extension also using relocatable modules, these are handled with simple LOAD command. Then needed to write the thing as new BASIC instructios or functions.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.25. 20:24:54
The code  to convert is very simple and short, it is not necessary to change pages, only an EXOs call to print characters to the EDITOR channel.

I know it is un-elegant and ugly... but it is a challenge for me to write a program that doesn't need absolute addresses nor auto-modifiable code. Doing it needs a twist of the mind. 10 instructions or more in exchange of only one... At least simulating a JP is easier....

I think I have seen that call to a JP (HL) used on EXOS.


I will do a version of each one to see.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.25. 21:16:46
EXOS have a support for a relocatable modules, header 02h
1) little code needed which is using EXOS 30 for load the remaining code from relocatable module
2) IS-BASIC extension also using relocatable modules, these are handled with simple LOAD command. Then needed to write the thing as new BASIC instructios or functions.

I know, header 02H, once in a time I decoded the "Mordon's quest" adventure only searching for the vocabulary, at the end I found the game rules and the map.... Without EXDOS controller, only tape and a printer, with a Basic listing, reading the flow of 1s and 0s. I was very young and used to thought that I was the only Enterprise owner in Spain. Today I have less knowledge than then...

Recently I have also decoded the first version of the Mouse.xr(extension relocatable) driver. But this time searching the memory of the emulator...


---
I don't want to load Basic extensions, I like the code to run on all Enterprises. But we lack the utility to make relocatable modules.

I remember another app decoded with the emulator, it was that Joystick driver (https://enterpriseforever.com/other-topics/re-looking-for-ep128/msg52656/#msg52656) listing submitted by an user to a Dutch magazine.

On classic times it must have been a very normal application. Why it still doesn't surface?

It is a good challenge, if I decoded the game with a Basic listing, another listing is enough to do the encoding task. Then, once Ziiiped, it can make the task at a reasonable speed. Needed are two binaries of the same file compiled at different addresses, one of them at 0000h.
Title: Re: Easy relocatable code in basic
Post by: BruceTanner on 2018.April.25. 21:26:38
The real problem I found about doing relocatable code with the Z80 is the impossibility to read the PC register to know the address of the instruction the processor is actually executing.
Here's a bit of a wild idea if you know interrupts are enabled:
Code: [Select]
        HALT
        DI
        DEC SP
        DEC SP
        POP HL    ; HL=address of DI instruction :-)
        EI

(untested :mrgreen: )
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.25. 23:15:09
Thanks! It can make the experiment more weird, even without the first absolute address at the start....
Title: Re: Easy relocatable code in basic
Post by: IstvanV on 2018.April.26. 16:55:18
Simple program to create EXOS module type 7 (relocatable extension):

[attachurl=1]

The input is raw machine code that is compiled at org 0000h, and the code is repeated twice. With sjasm, this is achieved by including the original source file from another file and using MODULE to avoid duplicate labels.
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2018.April.26. 19:17:34
Simple program to create EXOS module type 7 (relocatable extension):
Working! :smt038
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.26. 20:19:17
Thanks! I have to try it first. This can work with an extension, like Mouse.xr.
Title: Re: Easy relocatable code in basic
Post by: BruceTanner on 2018.April.26. 21:22:32
:smt041 :smt041 :smt041
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.27. 12:09:23
Some silly questions:

With an Hex editor, I have changed the module type to 02 on byte 1 on the header of the dbasx.xr file created by Zozo. I have also put 0FFh on bytes 4 and 5 of the header(no offset). It has loaded correctly without installing the extension.

-Is this the procedure?

-How can I create raw machine code with sjasm? The executable file is not admitted by reloc.
Title: Re: Easy relocatable code in basic
Post by: IstvanV on 2018.April.27. 13:36:01
With an Hex editor, I have changed the module type to 02 on byte 1 on the header of the dbasx.xr file created by Zozo. I have also put 0FFh on bytes 4 and 5 of the header(no offset). It has loaded correctly without installing the extension.

-Is this the procedure?

I tried the same, it is even in reloc.cpp as commented out code, but type 2 modules apparently need to be written as BASIC extensions, I do not know how to do that, so I changed it to type 7.

Quote
-How can I create raw machine code with sjasm? The executable file is not admitted by reloc.

There is a simple example in the .zip file and also Zozosoft's dbasx extension, you need to compile reloc2.s or dbasx2.s to create a file that is accepted by reloc.exe. reloc2.s contains only these lines:
Code: ZiLOG Z80 Assembler
  1.         org     0000h
  2.  
  3.         module  Reloc_0
  4.         include "reloc.s"
  5.         endmod
  6.  
  7.         module  Reloc_1
  8.         include "reloc.s"
  9.         endmod
The actual source code is in reloc.s, the reason why it is compiled in two instances is that reloc.exe needs this to find the absolute addresses (16-bit words) that require relocation.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.April.27. 18:59:52
I forgot to remove all ORGs and ENDs from the code....
Title: Re: Easy relocatable code in basic
Post by: dangerman on 2018.May.03. 10:51:15
I tried using ASMON in the past to assemble relocatable modules (it was to play around with some BASIC extensions actually). I used .CSEG and .ASEG but I found that it didn't work properly for me (I seem to remember that it didn't write the last byte properly or something). Maybe I was doing something wrong.

But... did you know that Hisoft Devpac will create relocatable modules? And it automatically knows which values are addresses and which aren't. I used it several times successfully to create relocatable modules.

Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2018.May.03. 11:04:18
did you know that Hisoft Devpac will create relocatable modules? And it automatically knows which values are addresses and which aren't. I used it several times successfully to create relocatable modules.
Yes. Just I don't liked too much the GEN :oops: But I only wrote few examples as relocatable, 99% of my programs are fixed :-)
Today I prefer Sjasm :-)
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.May.03. 12:33:54

But... did you know that Hisoft Devpac will create relocatable modules? And it automatically knows which values are addresses and which aren't. I used it several times successfully to create relocatable modules.

Then, maybe Devpac was the application used to make those classic relocatable programs.
Title: Re: Easy relocatable code in basic
Post by: dangerman on 2018.May.03. 18:39:57
Then, maybe Devpac was the application used to make those classic relocatable programs.

Yes... I don't know for sure but I always assumed that they were written in Devpac. I think in the early days Devpac was the only assembler available, although ASMON appears to have been around in late summer 1986 (according to the IEUG magazines).

Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.May.08. 11:13:26
By the way... Does anyone have the English manual? Thanks


Google translated Magyar (https://translate.google.com/translate?sl=hu&tl=en&js=y&prev=_t&hl=es&ie=UTF-8&u=http%3A%2F%2Fwww.ep128.hu%2FEp_Konyv%2FHISOFT_Devpac.htm&edit-text=&act=url) is very hard for me....

It is not a bad translation, but Google also translates the commands. For example, on some part of the text:

Quote
Az
     A,, <ENTER>
parancs (az editorból kiadva) általában elegendő a fordításhoz; ez a forrást assembly lista nélkül fogja fordítani.
 

Is translated as:

Quote
The
The "<ENTER>
command (issued from the editor) is generally sufficient for translation; this source will be translated without assembly list.


Then, I have to read constantly the original to see what is the real syntax of the command.
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2018.May.08. 11:37:13
By the way... Does anyone have the English manual? Thanks
I have :-) Forgot to scan it :oops:

[attach=1]
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2018.May.08. 12:42:14
And, the original Hisoft Pascal manual?

By the way... I have found this resemble of David Link and Dave Nutkins, founders of HISOFT:

Quote
HiSOFT has been in existence since 1980, founded by David Link and Dave Nutkins. Originally we created software for the NASCOM 1 kit-built microcomputer but swiftly moved on to the ZX Spectrum, for which we created many esoteric items such as HiSOFT Devpac, HiSOFT C, HiSOFT BASIC, HiSOFT Pascal, UltraKit, Colt and much more.

After great success with the various incarnations of the Spectrum we ported our core titles (Devpac, C++ and Pascal) to many other Z80-based computers; Tatung Einstein, Newbrain, Memotech 512, Amstrad CPC& PCW, Elan Enterprise and more! 'Twas a lot of fun and, undoubtedly, this list will stir as much excitement in some people as David's favourite band since 1971, Genesis, do in him!

After the Z80 processor began to flag (shame!), we moved on to the 68000 which meant moving stuff over to the Atari ST and Commodore Amiga. This, along with many hardware projects (such as Megalosound, Replay 16, Clarity 16, Squirrel SCSI, VideoMaster etc.) kept us going through the 90s until, reluctantly, we were forced to take the PC seriously.

Having forged a close relationship with MAXON Computer in Germany throughout the Amiga and Atari years, it was natural for us to take on the UK mantle for their flagship product, CINEMA 4D, an exciting and now rather important 3D product. HiSOFT promoted, distributed and sold CINEMA 4D from 1997 until 2001, at which point David Link formed MAXON Computer Ltd and moved all things CINEMA 4D under the MAXON umbrella.

David worked at MAXON UK as the CEO until resigning for personal reasons in early 2003, after which he ran a successful pub and café with his partner, without whom it would not have been possible.

David now designs and maintains websites while owning and running a busy pub/guest house in Shanklin, Isle of Wight.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2020.February.17. 01:27:46
I would like to return to this topic, now that I am about to begin to transcript the FisherTechnick CPC Basic listings to IS-BASIC.


Let's say that we can make a mixed Basic-MachineCode program on the Enterprise.

One of the most valuables tools to make a subroutine aware of its position is to pass it its own start address. This method was hinted to me some time ago (https://enterpriseforever.com/programming/where-i-am/msg38070/#msg38070) by Zozo:

If the machine code subroutine has been defined with MC=HEX$("XX,XX,...") then, we can use CALL USR(MC,MC) to pass its start point  on the HL register pair. The only drawback is that we lose the option to pass data to the subroutine.

This would be convenient on short routines with a few jumps/calls or fixed positions. But the problems multiply with long code, all the juicy options of the Z80 involve absolute addressing, and it can be a problem to repositioning all the jumps and calls inside a big program.

A solution that I have found is one that has been there all the time: WORD$.

Imagine we have written a MC subroutine to print a text on the screen, for example:

Code: [Select]
start: ld a, 0        ;Channel to write
ld bc, 5       ;Length of the string
ld de, STRING  ;Adress of the string
EXOS 8              ;Write block
ret
STRING:   db "Hello"


The Basic program would look like this:

100 ALLOCATE  16
110 CODE TEXTO=HEX$("3E,00,01,05,00,11,XX,XX,F7,08,C9,48,65,6C,6C,6F")
120 CALL USR(TEXTO,0)

But this routine will not work, because we need to give DE the absolute address of the string, which we don't know.... but we already know it, if we modify the line 110:

110 CODE TEXTO=HEX$("3E,00,01,05,00,11")&WORD$(TEXTO+11)&HEX$("F7,08,C9,48,65,6C,6C,6F")

TEXTO is already defined at the start of the line, so when the execution reaches "WORD$(TEXTO+11)" it doesn't give "*** Variable not initialised."

[attachimg=1]

Please don't laugh too hard at me if this is common knowledge....
Title: Re: Easy relocatable code in basic
Post by: Zozosoft on 2020.February.17. 02:11:36
For these problems developed the EXOS header 02, User relocatable modules function.
Just need to allocate memory for it, and load it to the allocated buffer. During the loading the EXOS recalculate the direct addresses to valid address for the current loading location.

Look about IstvanV's SJasmEP project, if I remember right he added support of these.
Title: Re: Easy relocatable code in basic
Post by: gflorez on 2020.February.17. 14:10:50
Yes, thanks, IstvanV did a good work on this (https://enterpriseforever.com/programming/easy-relocatable-code-in-basic/msg70156/#msg70156) same thread.

I mean, the WORD$ function has been underused(by me) and it seems that this is the real task(inserted in a CODE definition) for which it was created.

Not so long ago I discovered (https://enterpriseforever.com/programozas/basic/msg74234/#msg74234) another use, to extract the 2 bytes of 16bit numbers:





Title: Re: Easy relocatable code in basic
Post by: elmer on 2021.January.02. 19:28:23
Simple program to create EXOS module type 7 (relocatable extension):
...
The input is raw machine code that is compiled at org 0000h, and the code is repeated twice. With sjasm, this is achieved by including the original source file from another file and using MODULE to avoid duplicate labels.

Thanks, that's a really clever idea!  :mrgreen:

I think that I'm going to have to steal that method.  ;-)


But... did you know that Hisoft Devpac will create relocatable modules? And it automatically knows which values are addresses and which aren't. I used it several times successfully to create relocatable modules.

Cool, I was wondering if there was any assembler that could create a relocatable module.

Good old Hisoft!  :cool:


Today I prefer Sjasm :-)

But of course, I agree with Zozosoft here, these days it is much easier to just build assembly-language programs on a PC, and then test them on ep128emu.

I'm finding that the virtual device feature in zOOm's SJASMPLUS (https://github.com/z00m128/sjasmplus) is making it really easy to do some pretty serious modifications to IS-DOS.