General Category > Programming

Pros & Cons of a universal Z80 loader, the BSOS (Bootstrap or Bullshit?)

(1/3) > >>

zhulien:
Hi Everyone,


If you had a universal loader that allows your program to run on as many Z80 platforms as possible, would you use it?  The loader itself would be tweaked for each platform, but your program wouldn't need to be as such.  Think of it as a mini-CP/M type concept.


On the platform, the alternate registers are setup to be used as:


- a (nested interrupt disables)
- b (0)
- de (actual os entry point)


To make a BSOS Call somewhat like CP/M but now to allow it to work no matter where os_entry is on the platform.


ld a, 'A'
exx
ld c, FN_OUTCHAR
call os_entry


A minimal set of standard functions would be provided as proof of concept, such as:


- FN_GETPLATFORM
- FN_GETCAPABILITIES
- FN_CLEARSCREEN
- FN_OUTCHAR
- FN_INCHAR


And expanded upon from there.


Example code of loader to be tweaked with a shell app that outputs 'A' in a loop.



--- Code: ---
(bsos)


os_init: di
exx
and a ; initialise a' with the number of nested interrupt disables
ld bc, 0 ; initialise bc' with 0
ld de, os_entry ; initialise de' with os_entry
exx

call isr_init ; patch the original ISR for our own
ei

call spawn_shell ; launch the os shell here

call isr_restore ; restore the original ISR and memory config
ret ; back to BASIC


; os entry point
; entry: c' = function
; alternative register set must be selected
; exit: all registers corrupt except a', bc', de'
; standard register set is selected

os_entry: call os_di ; disable interrupts (alternate regs must be selected)
call mem_set ; set memory state here if required (ie enable ROM)


ld hl, bc ; lookup function stored in c'
add hl, hl ; ld b, 0 not required as already is 0 in b'
add hl, jumpblock

ld c, (hl) ; read the function entry into bc'
inc hl
ld b, (hl)


push bc ; prepare to call function entry in bc'
exx ; swap back to normal register set
ret ; call the function

call mem_restore ; restore memory state if required (ie disable ROM)
exx
call os_ei ; enable interrupts (alternate regs must be selected)
exx
ret ; return to the caller


; disable interrupts with nesting
; entry: a' = current nest count
; alternative register set must be selected
; exit: all registers preserved
; alternative register set is selected

os_di: di ; can disable always
inc a ; a'++
ret


; enable interrupts with nesting
; entry: a' = current nest count
; alternative register set must be selected
; exit: all registers preserved
; alternative register set is selected

os_ei: and a ; they weren't disabled if a' == 0
ret z ; so return

dec a ; they were disabled so a'--
ret nz ; if still a' is not 0 then return
ei ; otherwise enable interrupts again
ret


jumpblock: db _getplatform, _getcapabilities
db _clearscreen, _outchar
db _inchar

isr_init: ret
isr_restore: ret
isr_entry: ret


mem_set: ret
mem_restore: ret


spawn_shell: ret ; todo load the shell


_getplatform: ret
_getcapabilities: ret
_clearscreen: ret
_outchar: ret
_inchar: ret











(os_shell app)


FN_GETPLATFORM equ 0
FN_GETCAPABILITIES equ 1
FN_CLEARSCREEN equ 2
FN_OUTCHAR equ 3
FN_INCHAR equ 4


app_entry: jr app_main


app_header: defb 1 ; app header version
defb 1, 0, 0 ; app version
defs 'os_shell',0 ; app name


os_entry: push de ; call the os
ret
ret


; disable interrupts with nesting
; entry: a' = current nest count
; standard register set must be selected
; exit: all registers preserved
; standard register set is selected

safe_di: exx
di ; can disable always
inc a ; a'++
exx
ret


; enable interrupts with nesting
; entry: a' = current nest count
; standard register set must be selected
; exit: all registers preserved
; standard register set is selected

safe_ei: exx
and a ; they weren't disabled if a' == 0
jr z, safe_ei_ret ; so return

dec a ; they were disabled so a'--
jr nz, safe_ei_ret ; if still a' is not 0 then return
ei ; otherwise enable interrupts again
safe_ei_ret: exx
ret

app_main: ld a, 'A' ; display the leter A
exx
ld c, FN_OUTCHAR
call os_entry


call safe_di
; TODO do something with interrupts disabled
call safe_ei

jr app_main



--- End code ---

zhulien:
Forgot to mention why?


Why not allow the same program to work on:  AMSDOS, CP/M, CP/M+, Sega SC3000, ZX Spectrum, Enterprise 128, Tatung Einstein, etc...


I can see many people will say... games will suck, not necessarily, depends on how we provide access to graphics libraries.


But, aside from games.  Imagine your cool assembler or disassembler, or file utility just working on everything?  Like CP/M but hopefully easier to port BSOS and more modern universal hardware access.


I'd like my program to have a wide audience.

m_dr_m:
Obvious pro: Z80 programmers unite!


Con: well some tools remains tied to the hardware. For orgams:
  * Bank connection (agree, we could build an abstraction around that).
  * More problematic: rupture + rasters for enhanced ergonomics.


Anyway that's a great idea I would happily use for the next iterations of CPC_T cruncher.

m_dr_m:
Con: Yet another standard!


In which ways it would improve CP/M?

andycadley:
I suspect that, much like CP/M, even little choices like where in the address space things need to live will break compatibility with some machines.


Even assuming you can use IM1, IY or the alternate registers breaks on a Sinclair machine for example.

Navigation

[0] Message Index

[#] Next page

Go to full version
Powered by SMFPacks Reactions Mod
Powered by SMFPacks Alerts Pro Mod
Powered by SMFPacks Mentions Pro Mod