Код:
;--- crt0.s for MSX-DOS - by Konami Man, 11/2004
; Advanced version: allows "int main(char** argv, int argc)",
; the returned value will be passed to _TERM on DOS 2,
; argv is always 0x100 (the startup code memory is recycled).
; Overhead: 112 bytes.
;
; Compile programs with --code-loc 0x170 --data-loc X
; X=0 -> global vars will be placed immediately after code
; X!=0 -> global vars will be placed at address X
; (make sure that X>0x100+code size)
.globl _main
.area _HEADER (ABS)
.org 0x0100 ;MSX-DOS .COM programs start address
;--- Step 1: Initialize globals
init: ld hl,#initb
push hl
ld hl,#gsinit-1
inita: inc hl
ld a,(hl)
inc a
jr z,inita
jp (hl)
;--- Step 2: Build the parameter pointers table on 0x100,
; and terminate each parameter with 0.
; MSX-DOS places the command line length at 0x80 (one byte),
; and the command line itself at 0x81 (up to 127 characters).
initb: ld hl,(#6)
ld sp,hl ; set SP = TPA top
dec h ; HL=SP-256
ex de,hl ; de=parloop destination
;* Check if there are any parameters at all
ld a,(#0x80)
or a
ld c,#0
jr z,cont
;* Terminate command line with 0
; (DOS 2 does this automatically but DOS 1 does not)
ld hl,#0x81
ld bc,(#0x80)
ld b,h ; #0
add hl,bc
ld (hl),b ; #0
;* Copy the command line processing code to 0xC000 and
; execute it from there, this way the memory of the original code
; can be recycled for the parameter pointers table.
; (The space from 0x100 up to "cont" can be used,
; this is room for about 40 parameters.
; No real world application will handle so many parameters.)
ld hl,#cont ;To continue execution at "cont"
push hl ;when the routine RETs
push de ;next ret = jmp parloop
ld hl,#parloop
ld c,#parloopend-#parloop ; bc
ldir ; BC=0
;* Initialize registers and jump to the loop routine
ld hl,#0x81 ;Command line pointer
; ld c,#0 ;Number of params found
ld ix,#0x100 ;Params table pointer
ret
;>>> Command line processing routine begin
;* Loop over the command line: skip spaces
parloop: ld a,(hl)
or a ;Command line end found?
ret z
cp #32
jr nz,parfnd
inc hl
jr parloop
;* Parameter found: add its address to params table...
parfnd: ld (ix),l
ld 1(ix),h
inc ix
inc ix
inc c
ld a,c ;protection against too many parameters
cp #40
ret nc
;* ...and skip chars until finding a space or command line end
parloop2: ld a,(hl)
or a ;Command line end found?
ret z
sub a,#32
jr nz,nospc ;If space found, set it to 0
;(string terminator)...
ld (hl),a ;#0
inc hl
jr parloop ;...and return to space skipping loop
nospc: inc hl
jr parloop2
parloopend:
;>>> Command line processing routine end
;* Command line processing done. Here, C=number of parameters.
cont: ld hl,#_HEAP_start
ld (_heap_top),hl
ld hl,#0x100
ld b,l ;#0
push bc ;Pass info as parameters to "main"
push hl
;--- Step 3: Call the "main" function
call _main
;--- Step 4: Program termination.
; Termination code for DOS 2 was returned on L.
ld c,#0x62 ;DOS 2 function for program termination (_TERM)
ld b,l
call 5 ;On DOS 2 this terminates; on DOS 1 this returns...
ld c,#0x0
jp 5 ;...and then this one terminates
;(DOS 1 function for program termination).
;--- Program code and data (global vars) start here
;* Place data after program code, and data init code after data
.area _CODE
_bios:: ; uchar bios(int FuncNo, int Param)
_bioshl:: ; int bioshl(int FuncNo, int Param)
ld hl,#2
ld d,h ; d=0
add hl,sp
ld e,(hl) ; Func No
inc hl
inc hl
ld c,(hl)
inc hl
ld b,(hl) ; Parameter
ld hl,(#1)
add hl,de
add hl,de
add hl,de
ld a,#8
cp e
jr nz,abios
jp (hl) ; return HL (16 bit)
abios: ld de,#bbios
push de
jp (hl)
bbios: ld l,a ; return A (8 bit)
ret
.area _DATA
_heap_top::
.dw 0
gsinit: .area _GSINIT
.area _GSFINAL
ret
;* These doesn't seem to be necessary... (?)
;.area _OVERLAY
;.area _HOME
;.area _BSS
.area _HEAP
_HEAP_start::