Newer
Older
uBix-Retro / dump / oa-2.0.9 / sysapps / init / init.a65
/****************************************************************************
   
    OS/A65 Version 2.0.0
    Multitasking Operating System for 6502 Computers

    Copyright (C) 1989-1998 Andre Fachat 

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

****************************************************************************/

/*
 * This process starts other processes from the ROM, using the normal
 * ROM link chain. It starts PK_PRG and PK_FS types only.
 *
 * The difference between PK_INIT type (like this one) and the above 
 * mentioned is that PK_INIT type processes do _not_ get the SENDBUF
 * with their command line, because the kernel is unable to alloc
 * more than one SEM_SENDBUF during startup which can only be released 
 * by an already started process!
 *
 * You can define INIT_VERBOSE if you want init to print out
 * some debugging/logging info.
 * If you define INIT_OUTDEV with the device number, this device is used
 * to print the info, otherwise device 0 is used.
 * 
 * If INIT_USE_STDLIB is defined, init uses the (old) STDIO library, otherwise
 * it will include its own printing routines if INIT_VERBOSE is defined.
 *
 * If INIT_MERGE is defined, then files can be started with their STDOUT/STDERR
 * sent to the same device as the init process.
 *
 * If INIT_LIB6502 is defined, then PK_LIB ROM entries are supported and
 * started with the lib6502 forkto call - or at least with an undocumented
 * derivate... (argh, horrible code...).
 */

/* 
 * In this exerimental version init also scans other 64k banks for
 * for the standard ROM link chain to start in the upper half.
 * It does not start PK_INIT/PK_DEV programs from other banks, though.
 * The (currently _one_) other bank to scan is defined with INIT_MMU_BANK.
 *
 * To achieve remapping of the upper 32k, it assumes linear mapping
 * in bank 0 when starting and remaps itself to $1***.
 *
 * This only works with the CS/A65 MMU CPU board!
 */

#include "kernel.i65"
#include "kdefs.i65"

#ifdef INIT_LIB6502
#echo init uses lib6502
#include "lib6502.i65"
#endif

#ifndef INIT_OUTDEV
#define INIT_OUTDEV 	0
#endif

          .(

start     .word ende            ; pointer to end of file in ROM
          .byt  PK_INIT+$80     ; file type = init task + auto-execute bit
          .word PRG             ; execution start
          .byt  3               ; RAM size needed, in 256-byte blocks
          .byt  >$ff-ROMSTART	; shared mem size in 256-byte blocks
          .byt  0               ; priority
          .word 0               ; stdin, stdout/stderr device number (ignored)
          .asc  "init",0,0      ; command line

	  .zero
pz	  .word 0
s1	  .byt 0
s2	  .byt 0
	  .text

#ifdef INIT_MMU
	.data
actbank	.byt 0
	.text
#endif

#ifdef INIT_RESTART

#ifndef INIT_MAXRESTART
#define	INIT_MAXRESTART	7
#endif

	.data
npid	.byt 0
kpid	.byt 0			; number of killed tasks

#ifdef INIT_MMU
bank	.dsb INIT_MAXRESTART	; bank where program resides
#endif

lpa	.dsb INIT_MAXRESTART	; ROM start address low
hpa	.dsb INIT_MAXRESTART	; ROM start address high
pid	.dsb INIT_MAXRESTART	; PID of started process
killed	.dsb INIT_MAXRESTART	; this can still overflow - non-restartable
				; tasks give signals too!
	.text
#endif

PRG	  .(
#ifdef INIT_MMU
#ifdef ROM
#print *
	lda #>*
	lsr
	lsr
	lsr
	lsr
#ifdef ROMTEST
	ora #$10
#endif
	pha
	ldy #1
	jsr SETBLK
	pla
	clc
	adc #1
	ldy #2
	jsr SETBLK
&oldpc=*
#print *
	*= (* & $0fff) | $1000
&newpc=*
#print *
	jmp *+3
#endif
#endif

#ifdef INIT_VERBOSE
	; first organize stream and set device accordingly
	jsr GETSTR
	bcs no_out
	stx s1
	ldy s1
	ldx #INIT_OUTDEV
	lda #DC_GS
	jsr DEVCMD
	ldx #INIT_OUTDEV
	lda #DC_TX_ON
	jsr DEVCMD
	sec
	ldx #STDOUT
	lda s1
	jsr DUP
no_out
	ldx #0
	jsr itout
#endif
#ifdef INIT_RESTART
	lda #<sigadr
	ldy #>sigadr
	sec
	jsr SETSIG

	lda #SIG_CHLD
	clc
	jsr SETSIG

	lda #0
	sta npid
	sta kpid
#endif
;.byt 2
#ifdef INIT_MMU
	lda #0
	jsr setbank
bankloop
#endif	
;.byt 2
	  lda #<ROMSTART
          sta pz
          lda #>ROMSTART
          sta pz+1

#ifdef INIT_MMU
	ldx #6
	ldy #17
magicl	lda (pz),y
	cmp magic,x
	bne nextbank
	iny
	dex
	bpl magicl
	lda (pz),y
	cmp pz
	bne nextbank
	iny
	lda (pz),y
	cmp pz+1
	bne nextbank
	jmp startloop

magic	.byt "MOR2ASO"

#endif

startloop
          ldy #0
          lda (pz),y
          iny
          and (pz),y
          cmp #$ff
          bne slx1

#ifdef INIT_MMU
nextbank
	lda actbank
	bne endloop
	lda #INIT_MMU_BANK
	jsr setbank
	jmp bankloop
#endif

endloop   

#ifdef INIT_RESTART
	  jmp restarts
#else
	  jmp TERM
#endif

slx1	jsr dostart
#ifdef INIT_RESTART
	bcs norestart

	ldy #P_KIND+2
	lda (pz),y
	and #$40
	beq norestart
	ldy npid
	cpy #INIT_MAXRESTART
	bcs norestart
#ifdef INIT_MMU
	lda actbank
	sta bank,y
#endif
	lda pz
	sta lpa,y
	lda pz+1
	sta hpa,y
	txa
	sta pid,y
	inc npid
#ifdef INIT_VERBOSE
	ldx #9
	jsr itout
#endif
#endif
norestart
          ldy #0
          lda (pz),y
          tax
          iny
          lda (pz),y
          sta pz+1
          stx pz
          jmp startloop

	.)

	.(
&getserr3 
	  ldx s2
	  lda #SC_EOF
	  jsr STRCMD
	  lda #SC_EOF
	  jsr STRCMD
	  jmp gs2

getserr2 
	  ldx s2
	  lda #SC_EOF
	  jsr STRCMD
	  jsr FRESTR
gs2
#ifdef INIT_VERBOSE
	  ldx #10
	  jsr itout
	  jsr gs
	  sec
	  rts
#endif
	  
getserr1  
#ifdef INIT_VERBOSE
	  ldx #6
	  jsr itout
#endif
gs
	  ldx s1
	  jsr FRESTR
#ifdef INIT_VERBOSE
	  sec
	  rts	;jmp inext
#endif
getserr
#ifdef INIT_VERBOSE
	  ldx #6
	  jsr itout
#endif
	  sec
	  rts


&getstrs  jsr GETSTR
          bcs getserr
          stx s1

#ifdef INIT_MERGE
#ifdef INIT_VERBOSE
	  ldy #P_DEV+3
	  lda (pz),y
	  cmp #INIT_OUTDEV
	  bne getnew

	  ldx #STDOUT
	  lda #SC_REG_WR
	  jsr STRCMD
	  lda #SC_REG_WR
	  jsr STRCMD
	  stx s2
	  jmp oldstr
getnew
#endif
#endif
          jsr GETSTR
	  bcs getserr1
getserr3a bcs getserr3
	  stx s2
	  lda #SC_REG_WR	; register second writer (for STDERR)
	  jsr STRCMD
          ldy #P_DEV+3
          lda (pz),y
          tax
	  pha
          ldy s2
          lda #DC_GS
          jsr DEVCMD
	  pla
	  bcs getserr2
	  tax
          lda #DC_TX_ON
          jsr DEVCMD
oldstr	
          ldy #P_DEV+2
          lda (pz),y
	  bmi noinput
          tax
	  pha
          ldy s1
          lda #DC_PS
          jsr DEVCMD
	  pla
	  bcs getserr3a
          tax
          lda #DC_RX_ON
          jsr DEVCMD
	  clc
	  rts
noinput
	  lda #SC_EOF
	  ldx s1
	  jmp STRCMD
	  .)

dostart	  .(
	  jsr YIELD	; give devices time to clear state for restart

          ldy #P_KIND+2
          lda (pz),y
          bpl slx2
          and #$3f
          cmp #PK_PRG
          beq iprg
          cmp #PK_FS
          beq ifs
#ifdef INIT_LIB6502
	  cmp #PK_LIB
	  bne slx2
	  jmp execlib
#endif
slx2    clc  
slx2a	jmp inext

ifs
          ldx #STDNUL
          stx s1
          stx s2
          bne ifs1

iprg	  jsr getstrs
	  bcs slx2a
ifs1      
	  clc
	  ldx #SEM_SENDBUF
	  jsr PSEM		; alloc PCBUF - also does serializing, as
				; forked process releases it
	  lda s2
          sta PCBUF+FORK_STDOUT
          sta PCBUF+FORK_STDERR
          lda s1
          sta PCBUF+FORK_STDIN
          ldy #P_PRIORITY+2
          lda (pz),y
          sta PCBUF+FORK_PRIORITY

          ldy #P_RAM+2
          lda (pz),y
          sta PCBUF+FORK_SIZE
          iny
          lda (pz),y
          sta PCBUF+FORK_SHARED

          ldy #P_ADDR+2
          lda (pz),y
          sta PCBUF+FORK_ADDR
          iny
          lda (pz),y
          sta PCBUF+FORK_ADDR+1

          ldy #P_NAME+2-1
cmdn      iny
          lda (pz),y
          sta PCBUF+FORK_NAME-P_NAME-2,y
          bne cmdn
	  cmp PCBUF+FORK_NAME-P_NAME-3,y	; last byte also 0?
	  bne cmdn
          iny

#ifdef INIT_VERBOSE
	tya
	pha
	ldx #1
	jsr itout
	ldy #0
ll	lda PCBUF+FORK_NAME,y
	beq lx
	jsr putc
	iny
	bne ll
	beq end
lx	lda PCBUF+FORK_NAME-1,y
	beq end
	lda #" "
	jsr putc
	iny
	bne ll
end
	ldx #3
	jsr itout
	pla
	tay
#endif	
	
          jsr FORK
	  bcc inext1
	 		; on error release streams -> auto-release devices
#ifdef INIT_VERBOSE
	  ldx #4
	  jsr itout
#endif

	  ldx s1
	  lda #SC_NUL
	  jsr STRCMD
	  ldx s2
	  lda #SC_EOF
	  jsr STRCMD
	  lda #SC_EOF
	  jsr STRCMD

	  sec
	  rts
	  ; jmp inext

inext1
#ifdef INIT_VERBOSE
	txa
	pha
	ldx #5
	jsr itout
	pla
	tax
	clc
#endif
inext	rts
	.)

#ifdef INIT_VERBOSE

	.(

m0	.asc "Init V1.0 booting^M^J",0
m1	.asc "Start ",34,0
m2=0
m3	.asc 34,":",0
m4	.asc " failed!^M^J",0
m5	.asc " ok!^M^J",0
m6	.asc "Couldn't alloc streams!^M^J",0
#ifdef INIT_RESTART
m7	.asc "^M^JReceived sigchld from ",0
m8 	=m7-3
m9	.asc "Prepared restart!^M^J",0
m10	.asc "Could not set device stream!^M^J",0
#endif

haddr	.byt >m0, >m1, >m2, >m3, >m4, >m5, >m6
#ifdef INIT_RESTART
	.byt >m7, >m8, >m9, >m10
#endif
laddr	.byt <m0, <m1, <m2, <m3, <m4, <m5, <m6
#ifdef INIT_RESTART
	.byt <m7, <m8, <m9, <m10
#endif

&itout	.(
	lda haddr,x
	tay
	lda laddr,x

&itxtout 
#ifdef INIT_USE_STDLIB
	jmp Txtout

hexout	=Hexout
putc	=Putc

#else
	.zero
tp	.word
	.text

	sta tp
	sty tp+1
	ldy #0
tol	lda (tp),y
	beq tole
	jsr putc
	iny
	bne tol
	inc tp+1
	bne tol
tole	rts
	.)

&hexout	pha
	lsr
	lsr
	lsr
	lsr
	jsr nibout
	pla
	and #$0f
nibout	clc
	adc #"0"
	cmp #"9"+1
	bcc putc
	adc #6

&putc	pha
	ldx #STDOUT
	jsr PUTC
	bcc ok
	cmp #E_NUL
	beq ok
	cmp #E_NOSTR
	beq ok
	jsr YIELD
	pla
	jmp putc
ok	pla
	rts
#endif
	.)
#endif

#ifdef INIT_RESTART

restarts .(
	jsr YIELD
	ldx kpid
	beq restarts

	lda killed
	ldx #0
l1
	cmp pid,x
	beq doit
	inx
	cpx #INIT_MAXRESTART
	bcc l1

rmpid	php
	sei
	ldx #0
ll	lda killed+1,x
	sta killed,x
	inx
	cpx kpid
	bcc ll
	dec kpid
	plp
	jmp restarts

doit
#ifdef INIT_MMU
	txa
	pha
	lda bank,x
	jsr setbank
	pla
	tax
#endif
	lda hpa,x
	sta pz+1
	lda lpa,x
	sta pz
	txa
	sei
	pha
	jsr dostart
	pla
	tay
	txa
	bcc ok
	lda #<-1
ok	sta pid,y
	cli
	jmp rmpid
	.)

sigadr	.(
	txa
	pha
	tya 
	pha
#ifdef INIT_VERBOSE
	ldx #7
	jsr itout
#endif
loop	jsr CHECKCHLD
	bcs end
	txa 
#ifdef INIT_VERBOSE
	pha
	jsr hexout
	lda #" "
	jsr putc
	pla
#endif
	php
	sei
	ldx kpid
	sta killed,x
	inx
	cpx #INIT_MAXRESTART
	bcs l1
	stx kpid
l1	plp			/* TODO: give message if overflow */
	jmp loop
end
#ifdef INIT_VERBOSE
	ldx #8
	jsr itout
#endif
	pla
	tay
	pla
	tax
	pla
	rti
	.)

#endif

#ifdef INIT_LIB6502
execlib	.(
	.bss
libbuf	.dsb 64
	.text

	jsr getstrs
	bcs end

	jsr GETSTR
	bcs end2
	txa
	pha

	ldx #SEM_SENDBUF
	clc
	jsr PSEM
	
	pla
	sta PCBUF+FORK_NAME
	pha

	lda s1
	sta PCBUF+FORK_STDIN
	lda s2
	sta PCBUF+FORK_STDOUT
	sta PCBUF+FORK_STDERR

	lda pz
	clc
	adc #P_NAME+2-3		; emulate lib6502 forkto struct
	sta THREADSAVE
	lda pz+1
	adc #0
	sta THREADSAVE+1

#ifdef INIT_VERBOSE
	ldx #1
	jsr itout
	ldy #3
ll	lda (THREADSAVE),y
	beq lx
	jsr putc
	iny
	bne ll
	beq end1
lx	cpy #3
	beq next
	dey
	lda (THREADSAVE),y
	iny
	cmp #0
	beq end1
next	lda #" "
	jsr putc
	iny
	bne ll
end1
	ldx #3
	jsr itout	
#endif
	pla
	jsr init_forkto		; extra jmp-point in lib6502 implementation
#ifdef INIT_VERBOSE
	php
	txa
	pha
	bcc ifork_ok
	ldx #4
	.byt $2c
ifork_ok ldx #5
	jsr itout
	pla
	tax
	plp
#endif
	rts

end2	jsr getserr3
end	rts	;jmp inext
	.)
#endif

#ifdef INIT_MMU

/* maps the upper half of the 64k bank to the current memory map */
setbank	.(
	pha
	asl
	asl
	asl
	asl
#ifdef ROMTEST
	bne sbok
	ora #$10
sbok
#endif
#ifdef INIT_ROM2TEST
	cmp #INIT_MMU_BANK<<4
	bne rom2ok
	ora #$08	; xors the bit to map to lower half
rom2ok
#endif
	sta actbank
	ldx #8
sbloop
	txa
	eor actbank
	pha
	txa
	tay
	pla
	jsr SETBLK
	inx
	cpx #15
	bcc sbloop
	pla
	sta actbank
	rts
	.)

#ifdef ROM
#print *
/* if in ROM, change back to pseudo-relocation mode */
	*= * - newpc + oldpc
#print *
#endif
#endif

ende      .)