; ****************************************************************************
; TRDOS386.ASM (TRDOS 386 Kernel - v2.0.0) - MAIN PROGRAM : trdosk6.s
; ----------------------------------------------------------------------------
; Last Update: 24/01/2016
; ----------------------------------------------------------------------------
; Beginning: 24/01/2016
; ----------------------------------------------------------------------------
; Assembler: NASM version 2.11 (trdos386.s)
; ----------------------------------------------------------------------------
; Derived from TRDOS Operating System v1.0 (8086) source code by Erdogan Tan
; XXXXXXXX.ASM (XX/XX/2011)
;
; Derived from 'Retro UNIX 386 Kernel - v0.2.1.0' source code by Erdogan Tan
; u1.s (27/17/2015)
; ****************************************************************************

; Retro UNIX 386 v1 Kernel (v0.2) - u1.s
; Last Modification: 27/12/2015

sysent: ; < enter to system call >
	 ;19/10/2015
	; 21/09/2015
	; 01/07/2015
	; 19/05/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 10/04/2013 - 18/01/2014 (Retro UNIX 8086 v1)
	;
	; 'unkni' or 'sysent' is sytem entry from various traps. 
	; The trap type is determined and an indirect jump is made to 
	; the appropriate system call handler. If there is a trap inside
	; the system a jump to panic is made. All user registers are saved 
	; and u.sp points to the end of the users stack. The sys (trap)
	; instructor is decoded to get the the system code part (see
	; trap instruction in the PDP-11 handbook) and from this 
	; the indirect jump address is calculated. If a bad system call is
	; made, i.e., the limits of the jump table are exceeded, 'badsys'
	; is called. If the call is legitimate control passes to the
	; appropriate system routine.
	;
	; Calling sequence:
	;	Through a trap caused by any sys call outside the system.
	; Arguments:
	;	Arguments of particular system call.	
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       System call number is in EAX register.
	;
	;       Other parameters are in EDX, EBX, ECX, ESI, EDI, EBP
	;	registers depending of function details.
  	;
	; 16/04/2015
        mov     [ss:u.sp], esp ; Kernel stack points to return address
	; save user registers
	push	ds
	push	es
	push	fs
	push	gs
	pushad  ; eax, ecx, edx, ebx, esp -before pushad-, ebp, esi, edi
	;
	; ESPACE = esp - [ss:u.sp] ; 4*12 = 48 ; 17/09/2015
	; 	(ESPACE is size of space in kernel stack 
	;	for saving/restoring user registers.)
	;
	push	eax ; 01/07/2015
	mov     ax, KDATA
        mov     ds, ax
        mov     es, ax
        mov     fs, ax
        mov     gs, ax
	mov	eax, [k_page_dir]
	mov	cr3, eax
	pop	eax ; 01/07/2015
	; 19/10/2015
	cld
	;
	inc	byte [sysflg]
		; incb sysflg / indicate a system routine is in progress
        sti 	; 18/01/2014
	jnz     panic ; 24/05/2013
		; beq 1f
		; jmp panic ; / called if trap inside system
;1:
	; 16/04/2015
	mov	[u.r0], eax
	mov	[u.usp], esp ; kernel stack points to user's registers
	;
		; mov $s.syst+2,clockp
		; mov r0,-(sp) / save user registers 
		; mov sp,u.r0 / pointer to bottom of users stack 
			   ; / in u.r0
		; mov r1,-(sp)
		; mov r2,-(sp)
		; mov r3,-(sp)
		; mov r4,-(sp)
		; mov r5,-(sp)
		; mov ac,-(sp) / "accumulator" register for extended
		             ; / arithmetic unit
		; mov mq,-(sp) / "multiplier quotient" register for the
		             ; / extended arithmetic unit
		; mov sc,-(sp) / "step count" register for the extended
		             ; / arithmetic unit
		; mov sp,u.sp / u.sp points to top of users stack
		; mov 18.(sp),r0 / store pc in r0
		; mov -(r0),r0 / sys inst in r0      10400xxx
		; sub $sys,r0 / get xxx code
	shl	eax, 2
		; asl r0 / multiply by 2 to jump indirect in bytes
	cmp	eax, end_of_syscalls - syscalls
		; cmp r0,$2f-1f / limit of table (35) exceeded
	;jnb	short badsys
		; bhis badsys / yes, bad system call
	cmc
	pushf	
	push	eax
 	mov 	ebp, [u.sp] ; Kernel stack at the beginning of sys call
	mov	al, 0FEh ; 11111110b
	adc	al, 0 ; al = al + cf
	and	[ebp+8], al ; flags (reset carry flag)
		; bic $341,20.(sp) / set users processor priority to 0 
				 ; / and clear carry bit
	pop	ebp ; eax
	popf
        jc      badsys
	mov	eax, [u.r0]
	; system call registers: EAX, EDX, ECX, EBX, ESI, EDI
	jmp	dword [ebp+syscalls]
		; jmp *1f(r0) / jump indirect thru table of addresses
		            ; / to proper system routine.
syscalls: ; 1:
	; 21/09/2015
	; 01/07/2015
	; 16/04/2015 (32 bit address modification) 
	dd sysrele	; / 0
	dd sysexit 	; / 1
	dd sysfork 	; / 2
	dd sysread 	; / 3
	dd syswrite 	; / 4
	dd sysopen 	; / 5
	dd sysclose 	; / 6
	dd syswait 	; / 7
	dd syscreat 	; / 8
	dd syslink 	; / 9
	dd sysunlink 	; / 10
	dd sysexec 	; / 11
	dd syschdir 	; / 12
	dd systime 	; / 13
	dd sysmkdir 	; / 14
	dd syschmod 	; / 15
	dd syschown 	; / 16
	dd sysbreak 	; / 17
	dd sysstat 	; / 18
	dd sysseek 	; / 19
	dd systell 	; / 20
	dd sysmount 	; / 21
	dd sysumount 	; / 22
	dd syssetuid 	; / 23
	dd sysgetuid 	; / 24
	dd sysstime 	; / 25
	dd sysquit 	; / 26
	dd sysintr 	; / 27
	dd sysfstat 	; / 28
	dd sysemt 	; / 29
	dd sysmdate 	; / 30
	dd sysstty 	; / 31
	dd sysgtty 	; / 32
	dd sysilgins 	; / 33
	dd syssleep 	; 34 ; Retro UNIX 8086 v1 feature only !
			     ; 11/06/2014
	dd sysmsg	; 35 ; Retro UNIX 386 v1 feature only !
			     ; 01/07/2015
	dd sysgeterr	; 36 ; Retro UNIX 386 v1 feature only !
			     ; 21/09/2015 - get last error number
end_of_syscalls:

error:
	; 17/09/2015
	; 03/09/2015
	; 01/09/2015
	; 09/06/2015
	; 13/05/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 10/04/2013 - 07/08/2013 (Retro UNIX 8086 v1)
	;
	; 'error' merely sets the error bit off the processor status (c-bit)
	; then falls right into the 'sysret', 'sysrele' return sequence.
	;
	; INPUTS -> none
	; OUTPUTS ->
	;	processor status - carry (c) bit is set (means error)
	;
	; 26/05/2013 (Stack pointer must be reset here! 
	; 	      Because, jumps to error procedure
	;	      disrupts push-pop nesting balance)
	;
	mov	ebp, [u.sp] ; interrupt (system call) return (iretd) address
	or	byte [ebp+8], 1  ; set carry bit of flags register
				 ; (system call will return with cf = 1)
		; bis $1,20.(r1) / set c bit in processor status word below
		               ; / users stack
	; 17/09/2015
	sub	ebp, ESPACE ; 48 ; total size of stack frame ('sysdefs.inc')
				 ; for saving/restoring user registers	
	;cmp	ebp, [u.usp]
	;je	short err0	
	mov	[u.usp], ebp
;err0:
	; 01/09/2015
	mov	esp, [u.usp] 	    ; Retro Unix 8086 v1 modification!
				    ; 10/04/2013
				    ; (If an I/O error occurs during disk I/O,
				    ; related procedures will jump to 'error'
				    ; procedure directly without returning to 
				    ; the caller procedure. So, stack pointer
                                    ; must be restored here.)
	; 13/05/2015
	; NOTE: (The last) error code is in 'u.error', it can be retrieved by
	;	'get last error' system call later. 	

	; 03/09/2015 - 09/06/2015 - 07/08/2013
	mov 	byte [u.kcall], 0 ; namei_r, mkdir_w reset

sysret: ; < return from system call>
	; 10/09/2015
	; 29/07/2015
	; 25/06/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 10/04/2013 - 23/02/2014 (Retro UNIX 8086 v1)
	;
	; 'sysret' first checks to see if process is about to be 
	; terminated (u.bsys). If it is, 'sysexit' is called.
	; If not, following happens:	 
	; 	1) The user's stack pointer is restored.
	;	2) r1=0 and 'iget' is called to see if last mentioned
	;	   i-node has been modified. If it has, it is written out
	;	   via 'ppoke'.
	;	3) If the super block has been modified, it is written out
	;	   via 'ppoke'.				
	;	4) If the dismountable file system's super block has been
	;	   modified, it is written out to the specified device
	;	   via 'ppoke'.
	;	5) A check is made if user's time quantum (uquant) ran out
	;	   during his execution. If so, 'tswap' is called to give
	;	   another user a chance to run.
	;	6) 'sysret' now goes into 'sysrele'. 
	;	    (See 'sysrele' for conclusion.)		
	;
	; Calling sequence:
	;	jump table or 'br sysret'
	; Arguments: 
	;	-	
	; ...............................................................
	;	
	; ((AX=r1 for 'iget' input))
	;	
	xor	ax, ax ; 04/05/2013
sysret0: ; 29/07/2015 (eax = 0, jump from sysexec)
	inc	al ; 04/05/2013
	cmp	[u.bsys], al ; 1
		; tstb u.bsys / is a process about to be terminated because
        jnb     sysexit ; 04/05/2013
		; bne sysexit / of an error? yes, go to sysexit
	;mov	esp, [u.usp] ; 24/05/2013 (that is not needed here)
		; mov u.sp,sp / no point stack to users stack
	dec 	al ; mov ax, 0
		; clr r1 / zero r1 to check last mentioned i-node
	call	iget
		; jsr r0,iget / if last mentioned i-node has been modified
		            ; / it is written out
	xor 	ax, ax ; 0
	cmp	[smod], al ; 0
		; tstb	smod / has the super block been modified
	jna	short sysret1
		; beq	1f / no, 1f
	mov	[smod], al ; 0
		; clrb smod / yes, clear smod
	mov	ebx, sb0 ;; 07/08//2013
   	or	word [ebx], 200h ;;
	;or	word [sb0], 200h ; write bit, bit 9
		; bis $1000,sb0 / set write bit in I/O queue for super block
		      	      ; / output
	; AX = 0
	call 	poke ; 07/08/2013
	; call	ppoke
	; AX = 0
		; jsr r0,ppoke / write out modified super block to disk
sysret1: ;1:
	cmp	[mmod], al ; 0
		; tstb	mmod / has the super block for the dismountable file
		           ; / system
	jna	short sysrel0
		; beq 1f / been modified?  no, 1f
	mov	[mmod], al ; 0	
		; clrb	mmod / yes, clear mmod
        ;mov    ax, [mntd]
        ;;mov   al, [mdev] ; 26/04/2013
	mov	ebx, sb1 ;; 07/08//2013
        ;;mov	[ebx], al
	;mov    [sb1], al
		; movb	mntd,sb1 / set the I/O queue
	or	word [ebx], 200h
	;or	word [sb1], 200h ; write bit, bit 9
		; bis $1000,sb1 / set write bit in I/O queue for detached sb
	call	poke ; 07/08/2013
	;call	ppoke 
		; jsr r0,ppoke / write it out to its device
        ;xor    al, al ; 26/04/2013       
;1:
		; tstb uquant / is the time quantum 0?
		; bne 1f / no, don't swap it out

sysrele: ; < release >
	; 14/10/2015
	; 01/09/2015
	; 24/07/2015
	; 14/05/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 10/04/2013 - 07/03/2014 (Retro UNIX 8086 v1)
	;
	; 'sysrele' first calls 'tswap' if the time quantum for a user is
	;  zero (see 'sysret'). It then restores the user's registers and
	; turns off the system flag. It then checked to see if there is
	; an interrupt from the user by calling 'isintr'. If there is, 
	; the output gets flashed (see isintr) and interrupt action is
	; taken by a branch to 'intract'. If there is no interrupt from
	; the user, a rti is made.
	;
	; Calling sequence:
	;	Fall through a 'bne' in 'sysret' & ?
	; Arguments:
	;	-	
	; ...............................................................
	;	
	; 23/02/2014 (swapret)
	; 22/09/2013
sysrel0: ;1:
	cmp	byte [u.quant], 0 ; 16/05/2013
		; tstb uquant / is the time quantum 0?
        ja      short swapret
		; bne 1f / no, don't swap it out
sysrelease: ; 07/12/2013 (jump from 'clock')
	call	tswap
		; jsr r0,tswap / yes, swap it out
;
; Retro Unix 8086 v1 feature: return from 'swap' to 'swapret' address.
swapret: ;1:
	; 10/09/2015
	; 01/09/2015
	; 14/05/2015
	; 16/04/2015 (Retro UNIX 386 v1 - 32 bit, pm modifications)
	; 26/05/2013 (Retro UNIX 8086 v1)
	; cli
	; 24/07/2015
	;
	;; 'esp' must be already equal to '[u.usp]' here ! 
	;; mov	esp, [u.usp]

	; 22/09/2013
	call	isintr
	; 20/10/2013
	jz	short sysrel1
	call	intract
		; jsr r0,isintr / is there an interrupt from the user
		;     br intract / yes, output gets flushed, take interrupt
		               ; / action
sysrel1:
	cli ; 14/10/2015
	dec	byte [sysflg]
		; decb sysflg / turn system flag off
	mov     eax, [u.pgdir]
	mov	cr3, eax  ; 1st PDE points to Kernel Page Table 0 (1st 4 MB)
			  ; (others are different than kernel page tables) 
	; 10/09/2015
	popad ; edi, esi, ebp, temp (icrement esp by 4), ebx, edx, ecx, eax
		; mov (sp)+,sc / restore user registers
		; mov (sp)+,mq
		; mov (sp)+,ac
		; mov (sp)+,r5
		; mov (sp)+,r4
		; mov (sp)+,r3
		; mov (sp)+,r2
	;
	mov	eax, [u.r0]  ; ((return value in EAX))
	pop	gs
	pop	fs
	pop	es
	pop	ds
	iretd	
		; rti / no, return from interrupt

badsys:
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; (Major Modification: 'core' dumping procedure in
        ;       original UNIX v1 and Retro UNIX 8086 v1
	;	has been changed to print 'Invalid System Call !'
	;	message on the user's console tty.)
	; (EIP, EAX values will be shown on screen with error message)
	; (EIP = Return address just after the system call -INT 30h-)
	; (EAX = Function number)  
	;
	inc	byte [u.bsys]
	;
	mov	ebx, [u.sp] ; esp at the beginning of 'sysent'
	mov	eax, [ebx] ; EIP (return address, not 'INT 30h' address)
	call	dwordtohex
	mov	[bsys_msg_eip], edx
	mov	[bsys_msg_eip+4], eax
	mov	eax, [u.r0]
	call	dwordtohex
	mov	[bsys_msg_eax], edx
	mov	[bsys_msg_eax+4], eax
	xor	eax, eax
        mov     dword [u.base], badsys_msg ; "Invalid System call !"
	mov	ebx, [u.fofp]
	mov	[ebx], eax
	;mov	eax, 1 ; inode number of console tty (for user)	
	inc	eax
	mov	dword [u.count], BSYS_M_SIZE
		; writei
		; INPUTS ->
		;    r1 - inode number
		;    u.count - byte count to be written
		;    u.base - points to user buffer
		;    u.fofp - points to word with current file offset
		; OUTPUTS ->
		;    u.count - cleared
		;    u.nread - accumulates total bytes passed back	
		;
		; ((Modified registers: EDX, EBX, ECX, ESI, EDI, EBP)) 	
	call	writei
	;mov	eax, 1
	jmp	sysexit

		; incb u.bsys / turn on the user's bad-system flag
		; mov $3f,u.namep / point u.namep to "core\0\0"
		; jsr r0,namei / get the i-number for the core image file
		; br 1f / error
		; neg r1 / negate the i-number to open the core image file
		       ; / for writing
		; jsr r0,iopen / open the core image file
		; jsr r0,itrunc / free all associated blocks
		; br 2f
;1:
		; mov $17,r1 / put i-node mode (17) in r1
		; jsr r0,maknod / make an i-node
		; mov u.dirbuf,r1 / put i-node number in r1
;2:
		; mov $core,u.base / move address core to u.base
		; mov $ecore-core,u.count / put the byte count in u.count
		; mov $u.off,u.fofp / more user offset to u.fofp
		; clr u.off / clear user offset
		; jsr r0,writei / write out the core image to the user
		; mov $user,u.base / pt. u.base to user
		; mov $64.,u.count / u.count = 64
		; jsr r0,writei / write out all the user parameters
		; neg r1 / make i-number positive
		; jsr r0,iclose / close the core image file
		; br sysexit /
;3:
		; <core\0\0>

intract: ; / interrupt action
	; 14/10/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 09/05/2013 - 07/12/2013 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 modification !
	; (Process/task switching and quit routine by using
	; Retro UNIX 8086 v1 keyboard interrupt output.))
	;
	; input -> 'u.quit'  (also value of 'u.intr' > 0)
	; output -> If value of 'u.quit' = FFFFh ('ctrl+brk' sign)
	;		'intract' will jump to 'sysexit'.
	;	    Intract will return to the caller 
	;		if value of 'u.quit' <> FFFFh. 	 
	; 14/10/2015
	sti
	; 07/12/2013	
	inc 	word [u.quit]
	jz	short intrct0 ; FFFFh -> 0
	dec	word [u.quit]
	; 16/04/2015
	retn
intrct0:	
	pop	eax ; call intract -> retn
	;
	xor 	eax, eax
	inc	al  ; mov ax, 1
;;;
	; UNIX v1 original 'intract' routine... 
	; / interrupt action
		;cmp *(sp),$rti / are you in a clock interrupt?
		; bne 1f / no, 1f
		; cmp (sp)+,(sp)+ / pop clock pointer
	; 1: / now in user area
		; mov r1,-(sp) / save r1
		; mov u.ttyp,r1 
			; / pointer to tty buffer in control-to r1
		; cmpb 6(r1),$177
			; / is the interrupt char equal to "del"
		; beq 1f / yes, 1f
		; clrb 6(r1) 
		        ; / no, clear the byte 
			; / (must be a quit character)
		; mov (sp)+,r1 / restore r1
		; clr u.quit / clear quit flag
		; bis $20,2(sp) 
		    	; / set trace for quit (sets t bit of 
			; / ps-trace trap)
		; rti   ;  / return from interrupt
	; 1: / interrupt char = del
		; clrb 6(r1) / clear the interrupt byte 
			   ; / in the buffer
		; mov (sp)+,r1 / restore r1
		; cmp u.intr,$core / should control be 
				; / transferred to loc core?
		; blo 1f
		; jmp *u.intr / user to do rti yes, 
				; / transfer to loc core
	; 1:
		; sys 1 / exit

sysexit: ; <terminate process>
	; 01/09/2015
	; 31/08/2015
	; 14/05/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/04/2013 - 14/02/2014 (Retro UNIX 8086 v1)
	;
	; 'sysexit' terminates a process. First each file that
	; the process has opened is closed by 'flose'. The process
	; status is then set to unused. The 'p.pid' table is then
	; searched to find children of the dying process. If any of
	; children are zombies (died by not waited for), they are
	; set free. The 'p.pid' table is then searched to find the
	; dying process's parent. When the parent is found, it is
	; checked to see if it is free or it is a zombie. If it is
	; one of these, the dying process just dies. If it is waiting
	; for a child process to die, it notified that it doesn't 
	; have to wait anymore by setting it's status from 2 to 1
	; (waiting to active). It is awakened and put on runq by
	; 'putlu'. The dying process enters a zombie state in which
	; it will never be run again but stays around until a 'wait'
	; is completed by it's parent process. If the parent is not
	; found, process just dies. This means 'swap' is called with
	; 'u.uno=0'. What this does is the 'wswap' is not called
	; to write out the process and 'rswap' reads the new process
	; over the one that dies..i.e., the dying process is 
	; overwritten and destroyed.	
 	;
	; Calling sequence:
	;	sysexit or conditional branch.
	; Arguments:
	;	-	
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       System call number (=1) is in EAX register.
	;
	;       Other parameters are in EDX, EBX, ECX, ESI, EDI, EBP
	;       registers depending of function details.
	;
	; ('swap' procedure is mostly different than original UNIX v1.)
	;
; / terminate process
	; AX = 1
	dec 	ax ; 0
	mov	[u.intr], ax ; 0
		; clr u.intr / clear interrupt control word
		; clr r1 / clear r1
	; AX = 0
sysexit_1: ; 1:
	; AX = File descriptor
		; / r1 has file descriptor (index to u.fp list)
		; / Search the whole list
	call	fclose
		; jsr r0,fclose / close all files the process opened
	;; ignore error return
		; br .+2 / ignore error return
	;inc	ax
	inc	al
		; inc r1 / increment file descriptor
	;cmp	ax, 10
	cmp	al, 10
		; cmp r1,$10. / end of u.fp list?
	jb	short sysexit_1
		; blt 1b / no, go back
	movzx	ebx, byte [u.uno] ; 01/09/2015
		; movb	u.uno,r1 / yes, move dying process's number to r1
	mov	[ebx+p.stat-1], ah ; 0, SFREE, 05/02/2014
		; clrb p.stat-1(r1) / free the process
	;shl	bx, 1
	shl	bl, 1
		; asl r1 / use r1 for index into the below tables
	mov	cx, [ebx+p.pid-2]
		; mov p.pid-2(r1),r3 / move dying process's name to r3
	mov	dx, [ebx+p.ppid-2]
		; mov p.ppid-2(r1),r4 / move its parents name to r4
	; xor 	bx, bx ; 0
	xor	bl, bl ; 0
		; clr r2
	xor	esi, esi ; 0
		; clr r5 / initialize reg
sysexit_2: ; 1:
	        ; / find children of this dying process, 
		; / if they are zombies, free them
	;add	bx, 2
	add	bl, 2
		; add $2,r2 / search parent process table 
		          ; / for dying process's name
	cmp	[ebx+p.ppid-2], cx
		; cmp p.ppid-2(r2),r3 / found it?
	jne	short sysexit_4
		; bne 3f / no
	;shr	bx, 1
	shr	bl, 1
		; asr r2 / yes, it is a parent
	cmp	byte [ebx+p.stat-1], 3 ; SZOMB, 05/02/2014
		; cmpb p.stat-1(r2),$3 / is the child of this 
				     ; / dying process a zombie
	jne	short sysexit_3 
		; bne 2f / no
	mov	[ebx+p.stat-1], ah ; 0, SFREE, 05/02/2014
		; clrb p.stat-1(r2) / yes, free the child process
sysexit_3: ; 2:
	;shr	bx, 1
	shl	bl, 1
		; asl r2
sysexit_4: ; 3:
		; / search the process name table 
		; / for the dying process's parent
	cmp	[ebx+p.pid-2], dx ; 17/09/2013	
		; cmp p.pid-2(r2),r4 / found it?
	jne	short sysexit_5
		; bne 3f / no
	mov	esi, ebx
		; mov r2,r5 / yes, put index to p.pid table (parents
		          ; / process # x2) in r5
sysexit_5: ; 3:
	;cmp	bx, nproc + nproc
	cmp	bl, nproc + nproc
		; cmp r2,$nproc+nproc / has whole table been searched?
	jb	short sysexit_2
		; blt 1b / no, go back
		; mov r5,r1 / yes, r1 now has parents process # x2
	and	esi, esi ; r5=r1
	jz	short sysexit_6
		; beq 2f / no parent has been found. 
		       ; / The process just dies
	shr	si, 1
		; asr r1 / set up index to p.stat
	mov	al, [esi+p.stat-1]
		; movb p.stat-1(r1),r2 / move status of parent to r2
	and	al, al
	jz	short sysexit_6
		; beq 2f / if its been freed, 2f
	cmp	al, 3
		; cmp r2,$3 / is parent a zombie?
	je	short sysexit_6
		; beq 2f / yes, 2f
	; BH = 0
	mov	bl, [u.uno]
		; movb u.uno,r3 / move dying process's number to r3
	mov	byte [ebx+p.stat-1], 3  ; SZOMB, 05/02/2014
		; movb $3,p.stat-1(r3) / make the process a zombie
	; 05/02/2014
	cmp	al, 1 ; SRUN
	je	short sysexit_6
	;cmp	al, 2
		; cmp r2,$2 / is the parent waiting for 
			  ; / this child to die
	;jne	short sysexit_6	
		; bne 2f / yes, notify parent not to wait any more
	; 05/02/2014
	; p.stat = 2 --> waiting
	; p.stat = 4 --> sleeping
	mov	byte [esi+p.stat-1], 1 ; SRUN ; 05/02/2014
	;dec	byte [esi+p.stat-1]
		; decb	p.stat-1(r1) / awaken it by putting it (parent)
	mov	ax, si ; r1  (process number in AL)
	; 
	;mov	ebx, runq + 4
		; mov $runq+4,r2 / on the runq
	call	putlu
		; jsr r0, putlu
sysexit_6: ; 2:
	; 31/08/2015
		; / the process dies
	mov	byte [u.uno], 0
		; clrb u.uno / put zero as the process number, 
	           ; / so "swap" will
	call	swap
		; jsr r0,swap / overwrite process with another process
hlt_sys:
	;sti ; 18/01/2014
hlts0:
	hlt
	jmp	short hlts0
		; 0 / and thereby kill it; halt?


syswait: ; < wait for a processs to die >
	; 17/09/2015
	; 02/09/2015
	; 01/09/2015
	; 16/04/2015 (Retro UNIX 386 v1 - Beginning)
	; 24/05/2013 - 05/02/2014 (Retro UNIX 8086 v1)
	;
	; 'syswait' waits for a process die. 
	; It works in following way:
	;    1) From the parent process number, the parent's 
	; 	process name is found. The p.ppid table of parent
	;	names is then searched for this process name.
	;	If a match occurs, r2 contains child's process
	;	number. The child status is checked to see if it is
	;	a zombie, i.e; dead but not waited for (p.stat=3)
	;	If it is, the child process is freed and it's name
	;	is put in (u.r0). A return is then made via 'sysret'.
	;	If the child is not a zombie, nothing happens and
	;	the search goes on through the p.ppid table until
	;	all processes are checked or a zombie is found.
	;    2) If no zombies are found, a check is made to see if
	;	there are any children at all. If there are none,
	;	an error return is made. If there are, the parent's
	;	status is set to 2 (waiting for child to die),
	;	the parent is swapped out, and a branch to 'syswait'
	;	is made to wait on the next process.
	;
	; Calling sequence:
	;	?
	; Arguments:
	;	-
	; Inputs: - 
	; Outputs: if zombie found, it's name put in u.r0.	
	; ...............................................................
	;				
	
; / wait for a process to die

syswait_0:
	movzx	ebx, byte [u.uno] ; 01/09/2015
		; movb u.uno,r1 / put parents process number in r1
	shl	bl, 1
	;shl	bx, 1
		; asl r1 / x2 to get index into p.pid table
	mov	ax, [ebx+p.pid-2]
		; mov p.pid-2(r1),r1 / get the name of this process
	xor	esi, esi
		; clr r2
	xor	ecx, ecx ; 30/10/2013
	;xor 	cl, cl
		; clr r3 / initialize reg 3
syswait_1: ; 1:
	add	si, 2
		; add $2,r2 / use r2 for index into p.ppid table
			  ; / search table of parent processes 
			  ; / for this process name
	cmp	ax, [esi+p.ppid-2]
		; cmp p.ppid-2(r2),r1 / r2 will contain the childs 
			            ; / process number
	jne	short syswait_3
		;bne 3f / branch if no match of parent process name
	;inc	cx
	inc	cl
		;inc r3 / yes, a match, r3 indicates number of children
	shr	si, 1
		; asr r2 / r2/2 to get index to p.stat table
	; The possible states ('p.stat' values) of a process are:
	;	0 = free or unused
	;	1 = active
	;	2 = waiting for a child process to die
	;	3 = terminated, but not yet waited for (zombie).	
	cmp	byte [esi+p.stat-1], 3 ; SZOMB, 05/02/2014
		; cmpb p.stat-1(r2),$3 / is the child process a zombie?
	jne	short syswait_2
		; bne 2f / no, skip it
	mov	[esi+p.stat-1], bh ; 0
		; clrb p.stat-1(r2) / yes, free it
	shl	si, 1
		; asl r2 / r2x2 to get index into p.pid table
	movzx	eax, word [esi+p.pid-2]
	mov	[u.r0], eax
		; mov p.pid-2(r2),*u.r0 
			      ; / put childs process name in (u.r0)
	;
	; Retro UNIX 386 v1 modification ! (17/09/2015)
	;
	; Parent process ID -p.ppid- field (of the child process)
	; must be cleared in order to prevent infinitive 'syswait'
	; system call loop from the application/program if it calls
	; 'syswait' again (mistakenly) while there is not a zombie
	; or running child process to wait. ('forktest.s', 17/09/2015)
	;
	; Note: syswait will return with error if there is not a
	;       zombie or running process to wait.	
	;
	sub	ax, ax
	mov 	[esi+p.ppid-2], ax ; 0 ; 17/09/2015
	jmp	sysret0 ; ax = 0
	;
	;jmp	sysret
		; br sysret1 / return cause child is dead
syswait_2: ; 2:
	shl	si, 1
		; asl r2 / r2x2 to get index into p.ppid table
syswait_3: ; 3:
	cmp	si, nproc+nproc
		; cmp r2,$nproc+nproc / have all processes been checked?
	jb	short syswait_1
		; blt 1b / no, continue search
	;and	cx, cx
	and	cl, cl
		; tst r3 / one gets here if there are no children 
		       ; / or children that are still active
	; 30/10/2013
	jnz	short syswait_4
	;jz	error
		; beq error1 / there are no children, error
	mov	[u.r0], ecx ; 0
	jmp	error
syswait_4:
	mov	bl, [u.uno]
		; movb u.uno,r1 / there are children so put 
			      ; / parent process number in r1
	inc	byte [ebx+p.stat-1] ; 2, SWAIT, 05/02/2014
		; incb p.stat-1(r1) / it is waiting for 
				  ; / other children to die
	; 04/11/2013
	call	swap
		; jsr r0,swap / swap it out, because it's waiting
	jmp	syswait_0
		; br syswait / wait on next process

sysfork: ; < create a new process >
	; 18/09/2015
	; 04/09/2015
	; 02/09/2015
	; 01/09/2015
	; 28/08/2015
	; 14/05/2015
	; 10/05/2015
	; 09/05/2015
	; 06/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 24/05/2013 - 14/02/2014 (Retro UNIX 8086 v1)
	;
	; 'sysfork' creates a new process. This process is referred
	; to as the child process. This new process core image is
	; a copy of that of the caller of 'sysfork'. The only
	; distinction is the return location and the fact that (u.r0)
	; in the old process (parent) contains the process id (p.pid)
	; of the new process (child). This id is used by 'syswait'.
	; 'sysfork' works in the following manner: 	
	;    1) The process status table (p.stat) is searched to find
	;	a process number that is unused. If none are found
	;	an error occurs.
	;    2) when one is found, it becomes the child process number
	;	and it's status (p.stat) is set to active.
	;    3) If the parent had a control tty, the interrupt 
	;	character in that tty buffer is cleared.
	;    4) The child process is put on the lowest priority run 
	;	queue via 'putlu'.
	;    5) A new process name is gotten from 'mpid' (actually 
	;	it is a unique number) and is put in the child's unique
	;	identifier; process id (p.pid).
	;    6) The process name of the parent is then obtained and
	;	placed in the unique identifier of the parent process
	;	name is then put in 'u.r0'.	
	;    7) The child process is then written out on disk by
	;	'wswap',i.e., the parent process is copied onto disk
	;	and the child is born. (The child process is written 
	;	out on disk/drum with 'u.uno' being the child process
	;	number.)
	;    8) The parent process number is then restored to 'u.uno'.
	;    9) The child process name is put in 'u.r0'.
	;   10) The pc on the stack sp + 18 is incremented by 2 to
	;	create the return address for the parent process.
	;   11) The 'u.fp' list as then searched to see what files
	;	the parent has opened. For each file the parent has
	;	opened, the corresponding 'fsp' entry must be updated
	;	to indicate that the child process also has opened
	;	the file. A branch to 'sysret' is then made.	 			 				
	;
	; Calling sequence:
	;	from shell ?
	; Arguments:
	;	-
	; Inputs: -
	; Outputs: *u.r0 - child process name
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;	AX = r0 = PID (>0) (at the return of 'sysfork')
	;	= process id of child a parent process returns
	;	= process id of parent when a child process returns
	;
	;       In original UNIX v1, sysfork is called and returns as
	;	in following manner: (with an example: c library, fork)
	;	
	;	1:
	;		sys	fork
	;			br 1f  / child process returns here
	;		bes	2f     / parent process returns here
	;		/ pid of new process in r0
	;		rts	pc
	;	2: / parent process condionally branches here
	;		mov	$-1,r0 / pid = -1 means error return
	;		rts	pc
	;
	;	1: / child process brances here
	;		clr	r0   / pid = 0 in child process
	;		rts	pc
	;
	;	In UNIX v7x86 (386) by Robert Nordier (1999)
	;		// pid = fork();
	;		//
	;		// pid == 0 in child process; 
	;		// pid == -1 means error return
	;		// in child, 
	;		//	parents id is in par_uid if needed
	;		
	;		_fork:
	;			mov	$.fork,eax
	;			int	$0x30
	;			jmp	1f
	;			jnc	2f
	;			jmp	cerror
	;		1:
	;			mov	eax,_par_uid
	;			xor	eax,eax
	;		2:
	;			ret
	;
	;	In Retro UNIX 8086 v1,
	;	'sysfork' returns in following manner:
	;	
	;		mov	ax, sys_fork
	;		mov	bx, offset @f ; routine for child
	;		int	20h
	;		jc	error
	;		
	;	; Routine for parent process here (just after 'jc')
	;		mov	word ptr [pid_of_child], ax
	;		jmp	next_routine_for_parent	
	;
	;	@@: ; routine for child process here				
	;		....	
	;	NOTE: 'sysfork' returns to specified offset
	;	       for child process by using BX input.
	;	      (at first, parent process will return then 
	;	      child process will return -after swapped in-
	;	      'syswait' is needed in parent process
	;	      if return from child process will be waited for.)
	;	  				
	
; / create a new process
	; EBX = return address for child process 
	     ; (Retro UNIX 8086 v1 modification !)
	xor 	esi, esi
		; clr r1
sysfork_1: ; 1: / search p.stat table for unused process number
	inc	esi
		; inc r1
	cmp	byte [esi+p.stat-1], 0 ; SFREE, 05/02/2014
		; tstb p.stat-1(r1) / is process active, unused, dead
	jna	short sysfork_2	
		; beq 1f / it's unused so branch
	cmp	si, nproc
		; cmp r1,$nproc / all processes checked
	jb	short sysfork_1
		; blt 1b / no, branch back
	;
	; Retro UNIX 8086 v1. modification:
	;	Parent process returns from 'sysfork' to address 
	;	which is just after 'sysfork' system call in parent
	;	process. Child process returns to address which is put
	;	in BX register by parent process for 'sysfork'. 
	;
		;add $2,18.(sp) / add 2 to pc when trap occured, points
		             ; / to old process return
		; br error1 / no room for a new process
	jmp	error
sysfork_2: ; 1:
	call	allocate_page
	jc	error
	push	eax   ; UPAGE (user structure page) address
	; Retro UNIX 386 v1 modification!
	call	duplicate_page_dir
		; EAX = New page directory 
	jnc	short sysfork_3
	pop	eax   ; UPAGE (user structure page) address
	call 	deallocate_page
	jmp	error
sysfork_3:
	; Retro UNIX 386 v1 modification !
	push	esi
	call	wswap ; save current user (u) structure, user registers
		      ; and interrupt return components (for IRET)
	xchg	eax, [u.pgdir] ; page directory of the child process
	mov	[u.ppgdir], eax ; page directory of the parent process
	pop	esi
	pop	eax   ; UPAGE (user structure page) address
		; [u.usp] = esp
	mov	edi, esi
	shl	di, 2
	mov	[edi+p.upage-4], eax ; memory page for 'user' struct
	mov	[u.upage], eax ; memory page for 'user' struct (child)
	; 28/08/2015
	movzx	eax, byte [u.uno] ; parent process number
		; movb u.uno,-(sp) / save parent process number
	mov	edi, eax
        push	eax ; ** 
	mov     al, [edi+p.ttyc-1] ; console tty (parent)
	; 18/09/2015
	;mov     [esi+p.ttyc-1], al ; set child's console tty
	;mov     [esi+p.waitc-1], ah ; 0 ; reset child's wait channel
	mov     [esi+p.ttyc-1], ax ; al - set child's console tty
				   ; ah - reset child's wait channel	
	mov	eax, esi
	mov	[u.uno], al ; child process number
		;movb r1,u.uno / set child process number to r1
        inc     byte [esi+p.stat-1] ; 1, SRUN, 05/02/2014
		; incb p.stat-1(r1) / set p.stat entry for child 
				; / process to active status
		; mov u.ttyp,r2 / put pointer to parent process' 
			      ; / control tty buffer in r2
                ; beq 2f / branch, if no such tty assigned
		; clrb 6(r2) / clear interrupt character in tty buffer
	; 2:
	push	ebx  ; * return address for the child process
		     ; * Retro UNIX 8086 v1 feature only !	
	; (Retro UNIX 8086 v1 modification!)
		; mov $runq+4,r2
	call	putlu 
 		; jsr r0,putlu / put child process on lowest priority 
			   ; / run queue
	shl	si, 1
		; asl r1 / multiply r1 by 2 to get index 
		       ; / into p.pid table
	inc	word [mpid]
		; inc mpid / increment m.pid; get a new process name
	mov	ax, [mpid]
	mov	[esi+p.pid-2], ax
		;mov mpid,p.pid-2(r1) / put new process name 
				    ; / in child process' name slot
	pop	edx  ; * return address for the child process
		     ; * Retro UNIX 8086 v1 feature only !	
  	pop	ebx  ; **
	;mov	ebx, [esp] ; ** parent process number
		; movb (sp),r2 / put parent process number in r2
	shl 	bx, 1
		;asl r2 / multiply by 2 to get index into below tables
	;movzx eax, word [ebx+p.pid-2]
	mov	ax, [ebx+p.pid-2]
		; mov p.pid-2(r2),r2 / get process name of parent
				   ; / process
	mov	[esi+p.ppid-2], ax
		; mov r2,p.ppid-2(r1) / put parent process name 
			  ; / in parent process slot for child
	mov	[u.r0], eax	
		; mov r2,*u.r0 / put parent process name on stack 
			     ; / at location where r0 was saved
	mov 	ebp, [u.sp] ; points to return address (EIP for IRET)
	mov	[ebp], edx ; *, CS:EIP -> EIP
			   ; * return address for the child process
		; mov $sysret1,-(sp) /
		; mov sp,u.usp / contents of sp at the time when 
			      ; / user is swapped out
		; mov $sstack,sp / point sp to swapping stack space
	; 04/09/2015 - 01/09/2015
	; [u.usp] = esp
	push	sysret ; ***
	mov	[u.usp], esp ; points to 'sysret' address (***)
			     ; (for child process)	
	xor 	eax, eax
	mov 	[u.ttyp], ax ; 0
	;
	call	wswap ; Retro UNIX 8086 v1 modification !
		;jsr r0,wswap / put child process out on drum
		;jsr r0,unpack / unpack user stack
		;mov u.usp,sp / restore user stack pointer
		; tst (sp)+ / bump stack pointer
	; Retro UNIX 386 v1 modification !
	pop	eax ; ***
	shl	bx, 1
	mov     eax, [ebx+p.upage-4] ; UPAGE address ; 14/05/2015
	call	rswap ; restore parent process 'u' structure, 
		      ; registers and return address (for IRET)
		;movb (sp)+,u.uno / put parent process number in u.uno
        movzx   eax, word [mpid]
	mov	[u.r0], eax
		; mov mpid,*u.r0 / put child process name on stack 
			       ; / where r0 was saved
		; add $2,18.(sp) / add 2 to pc on stack; gives parent
			          ; / process return
	;xor	ebx, ebx
	xor     esi, esi
		;clr r1
sysfork_4: ; 1: / search u.fp list to find the files 
	      ; / opened by the parent process
	; 01/09/2015
	;xor	bh, bh
	;mov 	bl, [esi+u.fp]
	mov 	al, [esi+u.fp]
		; movb u.fp(r1),r2 / get an open file for this process
        ;or      bl, bl
	or	al, al
	jz	short sysfork_5	
		; beq 2f / file has not been opened by parent, 
		       ; / so branch
	mov	ah, 10 ; Retro UNIX 386 v1 fsp structure size = 10 bytes
	mul	ah
	;movzx	ebx, ax
	mov	bx, ax
	;shl     bx, 3
		; asl r2 / multiply by 8
       		; asl r2 / to get index into fsp table
       		; asl r2
  	inc     byte [ebx+fsp-2]
		; incb fsp-2(r2) / increment number of processes
			     ; / using file, because child will now be
			     ; / using this file
sysfork_5: ; 2:
        inc     esi
		; inc r1 / get next open file
        cmp     si, 10
		; cmp r1,$10. / 10. files is the maximum number which
			  ; / can be opened
	jb	short sysfork_4	
		; blt 1b / check next entry
	jmp	sysret
		; br sysret1

sysread: ; < read from file >
	; 13/05/2015
	; 11/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 23/05/2013 (Retro UNIX 8086 v1)
	;
	; 'sysread' is given a buffer to read into and the number of
	; characters to be read. If finds the file from the file
	; descriptor located in *u.r0 (r0). This file descriptor
	; is returned from a successful open call (sysopen).
	; The i-number of file is obtained via 'rw1' and the data
	; is read into core via 'readi'.
	;
	; Calling sequence:
	;	sysread; buffer; nchars
	; Arguments:
	;	buffer - location of contiguous bytes where 
	;		 input will be placed.
	;	nchars - number of bytes or characters to be read.
	; Inputs: *u.r0 - file descriptor (& arguments)
	; Outputs: *u.r0 - number of bytes read.	
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysread' system call has three arguments; so,
	;	* 1st argument, file descriptor is in BX register
	;	* 2nd argument, buffer address/offset in CX register
	;	* 3rd argument, number of bytes is in DX register
	;
	;	AX register (will be restored via 'u.r0') will return
	;	to the user with number of bytes read. 
	;
	call	rw1
	jc	error ; 13/05/2015, ax < 1
		; jsr r0,rw1 / get i-number of file to be read into r1
	test	ah, 80h
		; tst r1 / negative i-number?
	jnz	error
		; ble error1 / yes, error 1 to read
			   ; / it should be positive
	call	readi
		; jsr r0,readi / read data into core
	jmp	short rw0
		; br 1f
syswrite: ; < write to file >
	; 13/05/2015
	; 11/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 23/05/2013 (Retro UNIX 8086 v1)
	;
	; 'syswrite' is given a buffer to write onto an output file
	; and the number of characters to write. If finds the file
	; from the file descriptor located in *u.r0 (r0). This file 
	; descriptor is returned from a successful open or create call
	; (sysopen or syscreat). The i-number of file is obtained via
	; 'rw1' and buffer is written on the output file via 'write'.
	;
	; Calling sequence:
	;	syswrite; buffer; nchars
	; Arguments:
	;	buffer - location of contiguous bytes to be writtten.
	;	nchars - number of characters to be written.
	; Inputs: *u.r0 - file descriptor (& arguments)
	; Outputs: *u.r0 - number of bytes written.	
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'syswrite' system call has three arguments; so,
	;	* 1st argument, file descriptor is in BX register
	;	* 2nd argument, buffer address/offset in CX register
	;	* 3rd argument, number of bytes is in DX register
	;
	;	AX register (will be restored via 'u.r0') will return
	;	to the user with number of bytes written. 
	;
	call	rw1
	jc	error ; 13/05/2015, ax < 1
		; jsr r0,rw1 / get i-number in r1 of file to write
        test	ah, 80h
		; tst r1 / positive i-number ?
        jz	short rw3 ; 13/05/2015
	;jz	error
		; bge error1 / yes, error 1 
			   ; / negative i-number means write
        neg	ax
		; neg r1 / make it positive
	call	writei
        	; jsr r0,writei / write data
rw0: ; 1:
        mov	eax, [u.nread]
	mov	[u.r0], eax
		; mov u.nread,*u.r0 / put no. of bytes transferred
				  ; / into (u.r0)
	jmp	sysret
        	; br sysret1
rw1:	
	; 14/05/2015
	; 13/05/2015
	; 11/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 23/05/2013 - 24/05/2013 (Retro UNIX 8086 v1)
	; System call registers: bx, cx, dx (through 'sysenter')
	;
	;mov	[u.base], ecx 	; buffer address/offset 
				;(in the user's virtual memory space)
	;mov	[u.count], edx 
		; jsr r0,arg; u.base / get buffer pointer
        	; jsr r0,arg; u.count / get no. of characters
	;;mov	eax, ebx ; file descriptor
		; mov *u.r0,r1 / put file descriptor 
		             ; / (index to u.fp table) in r1
	; 13/05/2015
	mov	dword [u.r0], 0 ; r/w transfer count = 0 (reset)
	;
	;; call	getf
        ; eBX = File descriptor
	call	getf1 ; calling point in 'getf' from 'rw1'
		; jsr r0,getf / get i-number of the file in r1
	; AX = I-number of the file ; negative i-number means write
	; 13/05/2015
	cmp 	ax, 1
	jb	short rw2
	;
	mov	[u.base], ecx 	; buffer address/offset 
				;(in the user's virtual memory space)
	mov	[u.count], edx 
	; 14/05/2015
        mov     dword [u.error], 0 ; reset the last error code
	retn
        	; rts r0
rw2:
	; 13/05/2015
	mov	dword [u.error], ERR_FILE_NOT_OPEN ; file not open !
	retn
rw3: 
	; 13/05/2015
	mov	dword [u.error], ERR_FILE_ACCESS ; permission denied !
	stc
	retn

sysopen: ;<open file>
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 22/05/2013 - 27/05/2013 (Retro UNIX 8086 v1)
	;
	; 'sysopen' opens a file in following manner:
	;    1) The second argument in a sysopen says whether to
	;	open the file ro read (0) or write (>0).
	;    2) I-node of the particular file is obtained via 'namei'.
	;    3) The file is opened by 'iopen'.
	;    4) Next housekeeping is performed on the fsp table
	;	and the user's open file list - u.fp.
	;	a) u.fp and fsp are scanned for the next available slot.
	;	b) An entry for the file is created in the fsp table.
	;	c) The number of this entry is put on u.fp list.
	;	d) The file descriptor index to u.fp list is pointed
	;	   to by u.r0.
	;
	; Calling sequence:
	;	sysopen; name; mode
	; Arguments:
	;	name - file name or path name
	;	mode - 0 to open for reading
	;	       1 to open for writing
	; Inputs: (arguments)
	; Outputs: *u.r0 - index to u.fp list (the file descriptor)
	;		  is put into r0's location on the stack.	
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysopen' system call has two arguments; so,
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, mode is in CX register
	;
	;	AX register (will be restored via 'u.r0') will return
	;	to the user with the file descriptor/number 
	;	(index to u.fp list).
	;
	;call	arg2
	; * name - 'u.namep' points to address of file/path name
	;          in the user's program segment ('u.segmnt')
	;          with offset in BX register (as sysopen argument 1).
	; * mode - sysopen argument 2 is in CX register 
	;          which is on top of stack.
	;
	; jsr r0,arg2 / get sys args into u.namep and on stack
	;
       	; system call registers: ebx, ecx (through 'sysenter')

	mov	[u.namep], ebx
	push	cx
	call	namei
		; jsr r0,namei / i-number of file in r1
     	;and	ax, ax
	;jz	error ; File not found
	jc	short fnotfound ; 14/05/2015
	;jc	error ; 27/05/2013
		; br  error2 / file not found
   	pop	dx ; mode
	push	dx
	;or	dx, dx
	or	dl, dl
		; tst (sp) / is mode = 0 (2nd arg of call; 
		         ; / 0 means, open for read)
	jz	short sysopen_0
		; beq 1f / yes, leave i-number positive
syscreat_0: ; 27/12/2015
	neg	ax
        	; neg r1 / open for writing so make i-number negative
sysopen_0: ;1:
	call	iopen
		;jsr r0,iopen / open file whose i-number is in r1
	pop	dx
	;and	dx, dx
	and	dl, dl
        	; tst (sp)+ / pop the stack and test the mode
	jz	short sysopen_2
        	; beq op1 / is open for read op1
sysopen_1: ;op0:
	neg	ax
        	; neg r1 
		     ;/ make i-number positive if open for writing [???]
	;; NOTE: iopen always make i-number positive.
	;; Here i-number becomes negative again. [22/05/2013]
sysopen_2: ;op1:
        xor     esi, esi
        	; clr r2 / clear registers
        xor     ebx, ebx
		; clr r3
sysopen_3: ;1: / scan the list of entries in fsp table
        cmp     [esi+u.fp], bl ; 0
		; tstb u.fp(r2) / test the entry in the u.fp list
        jna      short sysopen_4
		; beq 1f / if byte in list is 0 branch
        inc     esi
		; inc r2 / bump r2 so next byte can be checked
        cmp     si, 10
		; cmp r2,$10. / reached end of list?
	jb	short sysopen_3
		; blt 1b / no, go back
toomanyf:
	; 14/05/2015
	mov	dword [u.error], ERR_TOO_MANY_FILES ; too many open files !
	jmp	error
        	; br error2 / yes, error (no files open)
fnotfound: 
	; 14/05/2015
	mov	dword [u.error], ERR_FILE_NOT_FOUND ; file not found !
	jmp	error

sysopen_4: ; 1:
        cmp     word [ebx+fsp], 0
		; tst fsp(r3) / scan fsp entries
        jna     short sysopen_5
		; beq 1f / if 0 branch
	; 14/05/2015 - Retro UNIX 386 v1 modification !
        add     bx, 10 ; fsp structure size = 10 bytes/entry
		; add $8.,r3 / add 8 to r3 
			; / to bump it to next entry mfsp table
        cmp     bx, nfiles*10
		; cmp r3,$[nfiles*8.] / done scanning
	jb	short sysopen_4
       		; blt 1b / no, back
	jmp	error
        	; br error2 / yes, error
sysopen_5: ; 1: / r2 has index to u.fp list; r3, has index to fsp table
        mov     [ebx+fsp], ax
		; mov r1,fsp(r3) / put i-number of open file 
			; / into next available entry in fsp table,
	mov	di, [cdev] ; word ? byte ?
        mov     [ebx+fsp+2], di ; device number
		; mov cdev,fsp+2(r3) / put # of device in next word
        xor	edi, edi
        mov     [ebx+fsp+4], edi ; offset pointer (0)
		; clr fsp+4(r3)
        mov     [ebx+fsp+8], di ; open count (0), deleted flag (0)
       		; clr fsp+6(r3) / clear the next two words
  	mov	eax, ebx
	mov	bl, 10
	div	bl 
		; asr r3
		; asr r3 / divide by 8 
		; asr r3 ; / to get number of the fsp entry-1
	inc	al
        	; inc r3 / add 1 to get fsp entry number
        mov     [esi+u.fp], al
		; movb r3,u.fp(r2) / move entry number into 
			; / next available slot in u.fp list
        mov     [u.r0], esi
		; mov r2,*u.r0 / move index to u.fp list 
			     ; / into r0 loc on stack
        jmp	sysret
		; br sysret2

	;
	; 'fsp' table (10 bytes/entry)
	; bit 15				   bit 0
	; ---|-------------------------------------------
	; r/w|		i-number of open file
	; ---|-------------------------------------------
	;		   device number
	; -----------------------------------------------
	; offset pointer, r/w pointer to file (bit 0-15)
	; -----------------------------------------------
	; offset pointer, r/w pointer to file (bit 16-31)
	; ----------------------|------------------------
	;  flag that says file 	| number of processes
	;   has been deleted	| that have file open 
	; ----------------------|------------------------
	;

syscreat: ; < create file >
	; 27/12/2015 (Retro UNIX 386 v1.1)
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 27/05/2013 (Retro UNIX 8086 v1)
	;
	; 'syscreat' called with two arguments; name and mode.
	; u.namep points to name of the file and mode is put
	; on the stack. 'namei' is called to get i-number of the file.		
	; If the file aready exists, it's mode and owner remain 
	; unchanged, but it is truncated to zero length. If the file
	; did not exist, an i-node is created with the new mode via
	; 'maknod' whether or not the file already existed, it is
	; open for writing. The fsp table is then searched for a free
	; entry. When a free entry is found, proper data is placed
	; in it and the number of this entry is put in the u.fp list.
	; The index to the u.fp (also know as the file descriptor)
	; is put in the user's r0. 			
	;
	; Calling sequence:
	;	syscreate; name; mode
	; Arguments:
	;	name - name of the file to be created
	;	mode - mode of the file to be created
	; Inputs: (arguments)
	; Outputs: *u.r0 - index to u.fp list 
	;		   (the file descriptor of new file)
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'syscreate' system call has two arguments; so,
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, mode is in CX register
	;
	;	AX register (will be restored via 'u.r0') will return
	;	to the user with the file descriptor/number 
	;	(index to u.fp list).
	;
	;call	arg2
	; * name - 'u.namep' points to address of file/path name
	;          in the user's program segment ('u.segmnt')
	;          with offset in BX register (as sysopen argument 1).
	; * mode - sysopen argument 2 is in CX register 
	;          which is on top of stack.
	;
        	; jsr r0,arg2 / put file name in u.namep put mode 
			    ; / on stack
	mov	[u.namep], ebx ; file name address
	push	cx ; mode
	call 	namei        	
		; jsr r0,namei / get the i-number
        ;and	ax, ax
	;jz	short syscreat_1	       	
	jc	short syscreat_1
		; br  2f / if file doesn't exist 2f
	; 27/12/2015
	cmp	ax, 41 ; device inode ?
        jb      syscreat_0 ; yes
	;
	neg 	ax
        	; neg r1 / if file already exists make i-number 
		       ; / negative (open for writing)
	call	iopen
        	; jsr r0,iopen /
	call	itrunc
        	; jsr r0,itrunc / truncate to 0 length
	pop	cx ; pop mode (did not exist in original Unix v1 !?)
        jmp     sysopen_1
        	; br op0
syscreat_1: ; 2: / file doesn't exist
	pop	ax
        	; mov (sp)+,r1 / put the mode in r1
	xor	ah, ah	
        	; bic $!377,r1 / clear upper byte
	call 	maknod
        	; jsr r0,maknod / make an i-node for this file
	mov	ax, [u.dirbuf]
        	; mov u.dirbuf,r1 / put i-number 
			        ; / for this new file in r1
        jmp     sysopen_1
        	; br op0 / open the file

sysmkdir: ; < make directory >
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 27/05/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'sysmkdir' creates an empty directory whose name is
	; pointed to by arg 1. The mode of the directory is arg 2.	
	; The special entries '.' and '..' are not present.
	; Errors are indicated if the directory already exists or		
	; user is not the super user. 
	;
	; Calling sequence:
	;	sysmkdir; name; mode
	; Arguments:
	;	name - points to the name of the directory
	;	mode - mode of the directory
	; Inputs: (arguments)
	; Outputs: -
	;    (sets 'directory' flag to 1; 
	;    'set user id on execution' and 'executable' flags to 0)
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysmkdir' system call has two arguments; so,
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, mode is in CX register
	;
		
; / make a directory

	;call	arg2
	; * name - 'u.namep' points to address of file/path name
	;          in the user's program segment ('u.segmnt')
	;          with offset in BX register (as sysopen argument 1).
	; * mode - sysopen argument 2 is in CX register 
	;          which is on top of stack.

		; jsr r0,arg2 / put file name in u.namep put mode 
			    ; / on stack
	mov	[u.namep], ebx
	push	cx ; mode
	call	namei
        	; jsr r0,namei / get the i-number
        	;     br .+4 / if file not found branch around error
        ;xor 	ax, ax
	;jnz	error
	jnc	short dir_exists ; 14/05/2015
	;jnc	error	
		; br  error2 / directory already exists (error)
	cmp	byte [u.uid], 0 ; 02/08/2013
        	;tstb u.uid / is user the super user
	jna	short dir_access_err ; 14/05/2015
	;jna	error
        	;bne error2 / no, not allowed
	pop	ax
        	;mov (sp)+,r1 / put the mode in r1
	and	ax, 0FFCFh ; 1111111111001111b
        	;bic $!317,r1 / all but su and ex
	;or	ax , 4000h ; 1011111111111111b
	or	ah, 40h ; Set bit 14 to 1
        	;bis $40000,r1 / directory flag
	call	maknod
        	;jsr r0,maknod / make the i-node for the directory
	jmp	sysret
        	;br sysret2 /
dir_exists:
	; 14/05/2015
	mov	dword [u.error], ERR_DIR_EXISTS ; dir. already exists !
	jmp	error
dir_access_err:
	; 14/05/2015
	mov	dword [u.error], ERR_DIR_ACCESS ; permission denied !
	jmp	error

sysclose: ;<close file>
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 22/05/2013 - 26/05/2013 (Retro UNIX 8086 v1)
	;
	; 'sysclose', given a file descriptor in 'u.r0', closes the
	; associated file. The file descriptor (index to 'u.fp' list)
	; is put in r1 and 'fclose' is called.
	;
	; Calling sequence:
	;	sysclose
	; Arguments:
	;	-  
	; Inputs: *u.r0 - file descriptor
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification:
	;	 The user/application program puts file descriptor
	;        in BX register as 'sysclose' system call argument.
	; 	 (argument transfer method 1)

	; / close the file
	
	mov 	eax, ebx
	call 	fclose
		; mov *u.r0,r1 / move index to u.fp list into r1
		; jsr r0,fclose / close the file
               	; br error2 / unknown file descriptor
		; br sysret2
	; 14/05/2015
	jnc	sysret
	mov	dword [u.error], ERR_FILE_NOT_OPEN ; file not open !
	jmp	error

sysemt:
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 10/12/2013 - 20/04/2014 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 modification: 
	;	'Enable Multi Tasking'  system call instead 
	;	of 'Emulator Trap' in original UNIX v1 for PDP-11.
	;
	; Retro UNIX 8086 v1 feature only!
	;	Using purpose: Kernel will start without time-out
	;	(internal clock/timer) functionality.
	;	Then etc/init will enable clock/timer for
	;	multi tasking. (Then it will not be disabled again
	;	except hardware reset/restart.)
	;

	cmp	byte [u.uid], 0 ; root ?
	;ja	error
	ja	badsys ; 14/05/2015
emt_0:
	cli
	and	ebx, ebx
	jz	short emt_2
	; Enable multi tasking -time sharing-
	mov	eax, clock
emt_1:
	mov	[x_timer], eax
	sti
	jmp	sysret
emt_2:
	; Disable multi tasking -time sharing-
	mov	eax, u_timer
	jmp	short emt_1

	; Original UNIX v1 'sysemt' routine
;sysemt:
        ;
	;jsr    r0,arg; 30 / put the argument of the sysemt call 
			 ; / in loc 30
        ;cmp    30,$core / was the argument a lower address 
			; / than core
        ;blo    1f / yes, rtssym
        ;cmp    30,$ecore / no, was it higher than "core" 
			; / and less than "ecore"
        ;blo    2f / yes, sysret2
;1:
        ;mov    $rtssym,30
;2:
        ;br     sysret2

sysilgins:
	; 14/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 03/06/2013
	; Retro UNIX 8086 v1 modification: 
	;	not a valid system call ! (not in use)
	;
	jmp	badsys
	;jmp	error
	;;jmp 	sysret

	; Original UNIX v1 'sysemt' routine
;sysilgins: / calculate proper illegal instruction trap address
        ;jsr    r0,arg; 10 / take address from sysilgins call
			  ;/ put it in loc 8.,
        ;cmp    10,$core / making it the illegal instruction 
		       ; / trap address
        ;blo    1f / is the address a user core address?  
		; / yes, go to 2f
        ;cmp    10,$ecore
        ;blo    2f
;1:
        ;mov    $fpsym,10 / no, make 'fpsum' the illegal 
		    ; / instruction trap address for the system
;2:
        ;br     sysret2 / return to the caller via 'sysret'

sysmdate: ; < change the modification time of a file >
	; 16/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 03/06/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'sysmdate' is given a file name. It gets inode of this 
	; file into core. The user is checked if he is the owner 
	; or super user. If he is neither an error occurs.
	; 'setimod' is then called to set the i-node modification
	; byte and the modification time, but the modification time
	; is overwritten by whatever get put on the stack during
	; a 'systime' system call. This calls are restricted to
	; the super user.		
	;
	; Calling sequence:
	;	sysmdate; name
	; Arguments:
	;	name - points to the name of file
	; Inputs: (arguments)
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;	 The user/application program puts address 
	;	 of the file name in BX register 
	;	 as 'sysmdate' system call argument.
	;
; / change the modification time of a file
		; jsr r0,arg; u.namep / point u.namep to the file name
        mov	[u.namep], ebx
	call	namei
		; jsr r0,namei / get its i-number
        jc	fnotfound ; file not found !
	;jc	error       
		; br error2 / no, such file
	call	iget
		; jsr r0,iget / get i-node into core
	mov	al, [u.uid]
	cmp	al, [i.uid]
        	; cmpb u.uid,i.uid / is user same as owner
	je	short mdate_1
        	; beq 1f / yes
	and	al, al
		; tstb u.uid / no, is user the super user
	;jnz	error
		; bne error2 / no, error
	jz	short mdate_1
	mov	dword [u.error], ERR_FILE_ACCESS ; permission denied !
	jmp	error
mdate_1: ;1:
	call	setimod
        	; jsr r0,setimod / fill in modification data,
		               ; / time etc.
	mov	esi, p_time
	mov	edi, i.mtim
	movsd
		; mov 4(sp),i.mtim / move present time to
        	; mov 2(sp),i.mtim+2 / modification time
        jmp	sysret
		; br sysret2

sysstty: ; < set tty status and mode >
	; 17/11/2015
	; 12/11/2015
	; 29/10/2015
	; 17/10/2015
	; 13/10/2015
	; 29/06/2015
	; 27/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 02/06/2013 - 12/07/2014 (Retro UNIX 8086 v1)
	;
	; 'sysstty' sets the status and mode of the typewriter 
	; whose file descriptor is in (u.r0).
	;
	; Calling sequence:
	;	sysstty; arg
	; Arguments:
	;	arg - address of 3 consequitive words that contain
	;	      the source of status data	
	; Inputs: ((*u.r0 - file descriptor & argument))
	; Outputs: ((status in address which is pointed to by arg))
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;	'sysstty' system call will set the tty
	;	(clear keyboard buffer and set cursor position)
	;	 in following manner:
	;   NOTE: All of tty setting functions are here (16/01/2014)
	;
	; Inputs:
	;	BX = 0 --> means
	;	   If CL = FFh
	;	      set cursor position for console tty, only 
	;	      CH will be ignored (char. will not be written)	
	;	   If CH = 0 (CL < FFh)
	;	      set console tty for (current) process
	;	      CL = tty number (0 to 9)
	;	      (If CH = 0, character will not be written)			
	;          If CH > 0 (CL < FFh)	
	;             CL = tty number (0 to 9)
	;	      CH = character will be written
	;	        at requested cursor position (in DX)	
	;	   DX = cursor position for tty number 0 to 7.	
  	;		(only tty number 0 to 7) 
	;          DL = communication parameters (for serial ports) 
	;	        (only for COM1 and COM2 serial ports)
	;	   DH < 0FFh -> DL is valid, initialize serial port
	;			or set cursor position	
	;	   DH = 0FFh -> DL is not valid
	;		do not set serial port parameters 
	;		or do not set cursor position
	;
	;	BX > 0 --> points to name of tty
	;    	   CH > 0 -->
	;		CH = character will be written in current 
	;            	cursor position (for tty number from 0 to 7)
	;	     	or character will be sent to serial port
	;	     	(for tty number 8 or 9)
	;		CL = color of the character if tty number < 8.
	;    	   CH = 0 --> Do not write a character, 
	;		set mode (tty 8 to 9) or 
	;		set current cursor positions (tty 0 to 7) only. 
	;   	   DX = cursor position for tty number 0 to 7.
	;    	   DH = FFh --> Do not set cursor pos (or comm. params.)
	;		(DL is not valid)
	;	   DL = communication parameters 
	;		for tty number 8 or 9 (COM1 or COM2).
	; Outputs:
	;	cf = 0 -> OK
	;	     AL = tty number (0 to 9)
	;	     AH = line status if tty number is 8 or 9
	;	     AH = process number (of the caller) 	
	;	cf = 1 means error (requested tty is not ready)
	;	     AH = FFh if the tty is locked 
	;		  (owned by another process)
	;	        = process number (of the caller) 
	;		  (if < FFh and tty number < 8)
	;	     AL = tty number (0FFh if it does not exist)
	;	     AH = line status if tty number is 8 or 9
	;	NOTE: Video page will be cleared if cf = 0.
	;
	; 27/06/2015 (32 bit modifications)
	; 14/01/2014
	xor 	eax, eax
	dec	ax ; 17/10/2015
	mov	[u.r0], eax ; 0FFFFh
	and	ebx, ebx
        jnz     sysstty_6
; set console tty
	; 29/10/2015
	; 17/01/2014 
	cmp	cl, 9
	jna	short sysstty_0
	; 17/11/2015
	cmp	cl, 0FFh
	jb	short sysstty_13
	mov	ch, cl ; force CH value to FFh 
sysstty_13:
	mov	bl, [u.uno] ; process number
	mov	cl, [ebx+p.ttyc-1] ; current/console tty
sysstty_0:
	; 29/06/2015
	push	dx
	push	cx
	xor 	dl, dl	; sysstty call sign
	mov	al, cl
	mov	[u.r0], al ; tyy number (0 to 9)
	call	ottyp
	pop	cx
	pop	dx
	;
	jc	short sysstty_pd_err
	;
	cmp	cl, 8
	jb	short sysstty_2
	;
	cmp	dh, 0FFh
	je	short sysstty_2
		; set communication parameters for serial ports
	; 29/10/2015
	mov	ah, dl ; communication parameters
		; ah = 0E3h = 11100011b = 115200 baud,
		;			 THRE int + RDA int 
		; ah = 23h = 00100011b = 9600 baud,
		;			 THRE int + RDA int 
	sub	al, al ; 0
	; 12/07/2014
	cmp	cl, 9
	jb	short sysstty_1
	inc	al
sysstty_1:
	push	cx
	; 29/06/2015	
	call 	sp_setp ; Set serial port communication parameters
	mov	[u.r0+1], cx ; Line status (ah)
			     ; Modem status (EAX bits 16 to 23)
	pop	cx
        jc      short sysstty_tmout_err ; 29/10/2015
sysstty_2:
	; 17/01/2014
	and	ch, ch 	; set cursor position 
			; or comm. parameters ONLY
	jnz	short sysstty_3
	movzx	ebx, byte [u.uno] ; process number
	mov	[ebx+p.ttyc-1], cl ; console tty
sysstty_3:
	; 16/01/2014
	mov	al, ch ; character  ; 0 to FFh
	; 17/11/2015
	mov 	ch, 7  ; Default color (light gray)
	cmp	cl, ch ; 7 (tty number)
        jna     sysstty_9
sysstty_12:
	;; BX = 0, CL = 8 or CL = 9
	; (Set specified serial port as console tty port)
	; CH = character to be written
	; 15/04/2014
	; CH = 0 --> initialization only
	; AL = character
	; 26/06/2014
	mov	[u.ttyn], cl
	; 12/07/2014
	mov	ah, cl ; tty number (8 or 9)
	and	al, al
	jz	short sysstty_4 ; al = ch = 0
 	; 04/07/2014
	call 	sndc
	; 12/07/2014
	jmp	short sysstty_5
sysstty_pd_err: ; 29/06/2015
	; 'permission denied !' error
	mov	dword [u.error], ERR_NOT_OWNER
	jmp	error
sysstty_4:
	; 12/07/2014
	;xchg 	ah, al	; al = 0 -> al = ah, ah = 0
	mov	al, ah ; 29/06/2015
	sub	al, 8
	; 27/06/2015
	call	sp_status ; get serial port status
	; AL = Line status, AH = Modem status
	; 12/11/2015
	cmp	al, 80h
	cmc
sysstty_5:
	mov	[u.r0+1], ax ; ah = line status
		     ; EAX bits 16-23 = modem status	
	pushf
	xor	dl, dl ; sysstty call sign
	mov	al, [u.ttyn] ; 26/06/2014
	call	cttyp
	popf
	jnc	sysret	; time out error 

sysstty_tmout_err:
	mov	dword [u.error], ERR_TIME_OUT
	jmp	error
sysstty_6:
	push	dx
	push	cx
	mov	[u.namep], ebx
	call	namei
	pop	cx
	pop	dx
	jc	short sysstty_inv_dn
	;
	cmp	ax, 19  ; inode number of /dev/COM2
	ja	short sysstty_inv_dn ; 27/06/2015
	;
	cmp	al, 10 ; /dev/tty0 .. /dev/tty7
		       ; /dev/COM1, /dev/COM2
	jb	short sysstty_7
	sub	al, 10
	jmp	short sysstty_8
sysstty_inv_dn: 
	; 27/06/2015
	; Invalid device name (not a tty) ! error
	; (Device is not a tty or device name not found)
	mov	dword [u.error], ERR_INV_DEV_NAME
	jmp	error 
sysstty_7:
	cmp	al, 1 ; /dev/tty
	jne	short sysstty_inv_dn ; 27/06/2015
	movzx	ebx, byte [u.uno] ; process number
	mov	al, [ebx+p.ttyc-1] ; console tty
sysstty_8:	
	mov	[u.r0], al
	push	dx
	push	ax
	push	cx	
	call	ottyp
	pop	cx
	pop	ax
	pop	dx
        jc      sysstty_pd_err ; 'permission denied !'
	; 29/10/2015
	xchg 	ch, cl
		; cl = character, ch = color code
	xchg	al, cl
		; al = character, cl = tty number
	cmp	cl, 7
        ja      sysstty_12
	;
	; 16/01/2014
	xor	bh, bh
	;
sysstty_9: 	; tty 0 to tty 7
	; al = character
	cmp	dh, 0FFh ; Do not set cursor position
	je	short sysstty_10
	push	cx
	push	ax	
	; movzx, ebx, cl
	mov	bl, cl ; (tty number = video page number)
	call	_set_cpos
	pop	ax
	pop	cx
sysstty_10: 
	; 29/10/2015
	or	al, al ; character
	jz      short sysstty_11 ; al = 0
	; 17/11/2015
	cmp	al, 0FFh
	jnb	short sysstty_11
		; ch > 0 and ch < FFh
	; write a character at current cursor position
	mov	ah, ch ; color/attribute
	; 12/07/2014
	push	cx
	call	_write_c_current
	pop	cx
sysstty_11:
	; 14/01/2014
	xor	dl, dl ; sysstty call sign
	; 18/01/2014
	;movzx	eax, cl ; 27/06/2015
	mov	al, cl
	call	cttyp
	jmp	sysret

; Original UNIX v1 'sysstty' routine:
; gtty:
;sysstty: / set mode of typewriter; 3 consequtive word arguments
        ;jsr    r0,gtty / r1 will have offset to tty block, 
	; 		/ r2 has source
        ;mov    r2,-(sp)
        ;mov    r1,-(sp) / put r1 and r2 on the stack
;1: / flush the clist wait till typewriter is quiescent
        ;mov    (sp),r1 / restore r1 to tty block offset
        ;movb   tty+3(r1),0f / put cc offset into getc argument
        ;mov    $240,*$ps / set processor priority to 5
        ;jsr    r0,getc; 0:../ put character from clist in r1
        ;       br .+4 / list empty, skip branch
        ;br     1b / get another character until list is empty
        ;mov    0b,r1 / move cc offset to r1
        ;inc    r1 / bump it for output clist
        ;tstb   cc(r1) / is it 0
        ;beq    1f / yes, no characters to output
 	;mov    r1,0f / no, put offset in sleep arg
        ;jsr    r0,sleep; 0:.. / put tty output process to sleep
        ;br     1b / try to calm it down again
;1:
        ;mov    (sp)+,r1
        ;mov    (sp)+,r2 / restore registers
	;mov    (r2)+,r3 / put reader control status in r3
        ;beq    1f / if 0, 1f
        ;mov    r3,rcsr(r1) / move r.c. status to reader
        ;                   / control status register
;1:
        ;mov    (r2)+,r3 / move pointer control status to r3
        ;beq    1f / if 0 1f
        ;mov    r3,tcsr(r1) / move p.c. status to printer 
	;		    / control status reg
;1:
        ;mov    (r2)+,tty+4(r1) / move to flag byte of tty block
        ;jmp     sysret2 / return to user

sysgtty: ; < get tty status >
	; 23/11/2015
	; 29/10/2015
	; 17/10/2015
	; 28/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 30/05/2013 - 12/07/2014 (Retro UNIX 8086 v1)
	;
	; 'sysgtty' gets the status of tty in question. 
	; It stores in the three words addressed by it's argument
	; the status of the typewriter whose file descriptor
	; in (u.r0).
	;
	; Calling sequence:
	;	sysgtty; arg
	; Arguments:
	;	arg - address of 3 words destination of the status
	; Inputs: ((*u.r0 - file descriptor))
	; Outputs: ((status in address which is pointed to by arg))
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;	'sysgtty' system call will return status of tty
	;	(keyboard, serial port and video page status)
	;	 in following manner:
	;
	; Inputs:
	;	BX = 0 --> means 
	;	     CH = 0 -->	'return status of the console tty' 
	;	                 for (current) process
	;	     CL = 0 --> return keyboard status (tty 0 to 9)
	;	     CL = 1 --> return video page status (tty 0 to 7)
	;	     CL = 1 --> return serial port status (tty 8 & 9)		
	;	     CH > 0 -->	tty number + 1
	;
	;	BX > 0 --> points to name of tty
	;	     CL = 0 --> return keyboard status
	;	     CL = 1 --> return video page status
	;	     CH = undefined		 
	;
	; Outputs:
	;	cf = 0 ->
	;
	;	     AL = tty number from 0 to 9
	;		  (0 to 7 is also the video page of the tty)	
	;	     AH = 0 if the tty is free/unused
	;	     AH = the process number of the caller 
 	;	     AH = FFh if the tty is locked by another process
	;
	;	  (if calling is for serial port status)
	;	     BX = serial port status if tty number is 8 or 9
	;		  (BH = modem status, BL = Line status)
	;	     CX = 0FFFFh (if data is ready)
	;	     CX = 0 (if data is not ready or undefined)		
	;
	;	  (if calling is for keyboard status)
	;	     BX = current character in tty/keyboard buffer
	;		  (BH = scan code, BL = ascii code)
	;		  (BX=0 if there is not a waiting character)
	;	     CX  is undefined
	;
	;	  (if calling is for video page status)	
	;	     BX = cursor position on the video page
	;		  if tty number < 8
	;		  (BH = row, BL = column)
	;	     CX = current character (in cursor position)
	;		  on the video page of the tty 
	;		  if tty number < 8
	;		  (CH = color, CL = character)
	;	
	;	cf = 1 means error (requested tty is not ready)
	;
	;	     AH = FFh if the caller is not owner of
	;		  specified tty or console tty
	;	     AL = tty number (0FFh if it does not exist)
	;	     BX, CX are undefined if cf = 1
	;
	;	  (If tty number is 8 or 9)
	;	     AL = tty number 
	;	     AH = the process number of the caller 
	;	     BX = serial port status
	;  		 (BH = modem status, BL = Line status)
	;	     CX = 0
	;
		
gtty:   ; get (requested) tty number
	; 17/10/2015
	; 28/06/2015 (Retro UNIX 386 v1 - 32 bit modifications)
	; 30/05/2013 - 12/07/2014
	; Retro UNIX 8086 v1 modification ! 
	;
	; ((Modified regs: eAX, eBX, eCX, eDX, eSI, eDI, eBP))
	;
	; 28/06/2015 (32 bit modifications)
	; 16/01/2014
	xor 	eax, eax
	dec	ax ; 17/10/2015
	mov 	[u.r0], eax ; 0FFFFh
	cmp	cl, 1
	jna	short sysgtty_0
sysgtty_invp:
	; 28/06/2015
        mov     dword [u.error], ERR_INV_PARAMETER ; 'invalid parameter !' 
	jmp	error
sysgtty_0:	
	and	ebx, ebx
	jz	short sysgtty_1
	;
	mov	[u.namep], ebx
	push	cx ; 23/11/2015
	call	namei
	pop	cx ; 23/11/2015
	jc 	short sysgtty_inv_dn ; 28/06/2015
	;
	cmp	ax, 1
	jna	short sysgtty_2
	sub	ax, 10
	cmp	ax, 9
	;ja	short sysgtty_inv_dn
	;mov	ch, al
	;jmp	short sysgtty_4
	; 23/11/2015
	jna	short sysgtty_4
sysgtty_inv_dn: 
	; 28/06/2015
	; Invalid device name (not a tty) ! error
	; (Device is not a tty or device name not found)
	mov	dword [u.error], ERR_INV_DEV_NAME
	jmp	error 
sysgtty_1:
	; 16/01/2014
	cmp	ch, 10
	ja	short sysgtty_invp ; 28/06/2015
	dec	ch ; 0 -> FFh (negative)
	jns	short sysgtty_3 ; not negative
	;
sysgtty_2:
	; get tty number of console tty
	mov	ah, [u.uno]
 	; 28/06/2015
	movzx 	ebx, ah
	mov	ch, [ebx+p.ttyc-1]
sysgtty_3:
	mov	al, ch
sysgtty_4:
	mov	[u.r0], al
 	; 28/06/2015
	;cmp	al, 9
	;ja	short sysgtty_invp
	mov	ebp, [u.usp]
	; 23/11/2015
	and	cl, cl
	jz	short sysgtty_6 ; keyboard status
	cmp	al, 8 ; cmp ch, 8
	jb	short sysgtty_6 ; video page status
	; serial port status
	; 12/07/2014
	;mov	dx, 0
	;je	short sysgtty_5
	;inc	dl
;sysgtty_5:
	; 28/06/2015
	sub	al, 8
	call	sp_status ; serial (COM) port (line) status
	; AL = Line status, AH = Modem status
	mov	[ebp+16], ax ; serial port status (in EBX)
	mov	ah, [u.uno]
        mov     [u.r0+1], ah
	mov	word [ebp+24], 0 ; data status (0 = not ready)	
				; (in ECX)
	test	al, 80h
	jnz	short sysgtty_dnr_err ; 29/06/2015
	test	al, 1
	jz	sysret
	dec	word [ebp+24] ; data status (FFFFh = ready)	
	jmp	sysret
sysgtty_6:
	mov	[u.ttyn], al ; tty number
	;movzx	ebx, al
	mov 	bl, al ; tty number (0 to 9)
	shl 	bl, 1  ; aligned to word
	; 22/04/2014 - 29/06/2015
        add     ebx, ttyl
 	mov	ah, [ebx]
	cmp	ah, [u.uno]
	je	short sysgtty_7
	and	ah, ah
	;jz	short sysgtty_7
	jnz	short sysgtty_8
	;mov	ah, 0FFh
sysgtty_7:
        mov     [u.r0+1], ah
sysgtty_8:
	or	cl, cl
	jnz	short sysgtty_9
	mov	ah, 1  ; test a key is available
	call	int16h ; 24/01/2016
	mov	[ebp+16], ax ; bx, character
	jmp	sysret
sysgtty_9:
	mov	bl, [u.ttyn]
	; bl = video page number
	call 	get_cpos
	; dx = cursor position
	mov	[ebp+16], dx ; bx
	;mov	bl, [u.ttyn]
	; bl = video page number
	call	_read_ac_current ; 24/01/2016
	; ax = character and attribute/color
	mov	[ebp+24], ax ; cx
	jmp	sysret
sysgtty_dnr_err:
	; 'device not responding !' error	
	;mov 	dword [u.error], ERR_TIME_OUT ; 25
	mov 	dword [u.error], ERR_DEV_NOT_RESP ;  25				
	jmp	error	

; Original UNIX v1 'sysgtty' routine:
; sysgtty:
        ;jsr    r0,gtty / r1 will have offset to tty block,
	;	       / r2 has destination
        ;mov    rcsr(r1),(r2)+ / put reader control status 
	;                     / in 1st word of dest
        ;mov    tcsr(r1),(r2)+ / put printer control status
	;                     / in 2nd word of dest
        ;mov    tty+4(r1),(r2)+ / put mode in 3rd word
        ;jmp    sysret2 / return to user
	
; Original UNIX v1 'gtty' routine:
; gtty:
        ;jsr    r0,arg; u.off / put first arg in u.off
        ;mov    *u.r0,r1 / put file descriptor in r1
        ;jsr    r0,getf / get the i-number of the file
        ;tst    r1 / is it open for reading
        ;bgt    1f / yes
        ;neg    r1 / no, i-number is negative, 
	;          / so make it positive
;1:
        ;sub    $14.,r1 / get i-number of tty0
        ;cmp    r1,$ntty-1 / is there such a typewriter
        ;bhis   error9 / no, error
        ;asl    r1 / 0%2
        ;asl    r1 / 0%4 / yes
        ;asl    r1 / 0%8 / multiply by 8 so r1 points to 
	;	       ; / tty block
        ;mov    u.off,r2 / put argument in r2
        ;rts    r0 / return

; Retro UNIX 386 v1 Kernel (v0.2) - u2.s
; Last Modification: 03/01/2016

syslink:
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/06/2013 (Retro UNIX 8086 v1)
	;
	; 'syslink' is given two arguments, name 1 and name 2.
	; name 1 is a file that already exists. name 2 is the name
	; given to the entry that will go in the current directory.
	; name2 will then be a link to the name 1 file. The i-number
	; in the name 2 entry of current directory is the same
	; i-number for the name 1 file.
	;
	; Calling sequence:
	;	syslink; name 1; name 2
	; Arguments:
	;	name 1 - file name to which link will be created.
	;	name 2 - name of entry in current directory that
	;		 links to name 1.
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       'syslink' system call has two arguments; so,
	;	* 1st argument, name 1 is pointed to by BX register
	;	* 2nd argument, name 2 is pointed to by CX register
	;
		; / name1, name2
		;jsr r0,arg2 / u.namep has 1st arg u.off has 2nd
	mov	[u.namep], ebx
	push	ecx
	call	namei
		; jsr r0,namei / find the i-number associated with
			     ; / the 1st path name
     	;;and	ax, ax
	;;jz	error ; File not found
	;jc	error 
		; br error9 / cannot be found
	jnc	short syslink0
	;pop 	ecx
	; 'file not found !' error
	mov	dword [u.error], ERR_FILE_NOT_FOUND ; 12
	jmp	error
syslink0:
	call	iget
		; jsr r0,iget / get the i-node into core
	pop	dword [u.namep] ; ecx
		; mov (sp)+,u.namep / u.namep points to 2nd name
	push	ax
		; mov r1,-(sp) / put i-number of name1 on the stack
			    ; / (a link to this file is to be created)
	push	word [cdev]
		; mov cdev,-(sp) / put i-nodes device on the stack
	call	isdir
		; jsr r0,isdir / is it a directory
	call	namei
		; jsr r0,namei / no, get i-number of name2
	;jnc	error
		; br .+4   / not found 
			 ; / so r1 = i-number of current directory
			 ; / ii = i-number of current directory
		; br error9 / file already exists., error
	jc	short syslink1
	; pop ax
	; pop ax
	; 'file exists !' error
	mov	dword [u.error], ERR_FILE_EXISTS ; 14
	jmp	error
syslink1:
	pop	cx
	;cmp	cx, [cdev]
	cmp	cl, [cdev]
	;jne	error
		; cmp (sp)+,cdev / u.dirp now points to 
			       ; / end of current directory
	        ; bne error9
	je	short syslink2
	; 'not same drive !' error
	mov	dword [u.error],  ERR_DRV_NOT_SAME ; 21
	jmp	error
syslink2:
	pop	ax
	push	ax
	mov	[u.dirbuf], ax
		; mov (sp),u.dirbuf / i-number of name1 into u.dirbuf
	call	mkdir
		; jsr r0,mkdir / make directory entry for name2 
		 	     ; / in current directory
	pop	ax
		; mov (sp)+,r1 / r1 has i-number of name1
	call	iget
		; jsr r0,iget / get i-node into core
	inc	byte [i.nlks]
		; incb i.nlks / add 1 to its number of links
	call	setimod
		; jsr r0,setimod / set the i-node modified flag
	jmp	sysret

isdir:
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 04/05/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'isdir' check to see if the i-node whose i-number is in r1
	;  is a directory. If it is, an error occurs, because 'isdir'
	;  called by syslink and sysunlink to make sure directories
	;  are not linked. If the user is the super user (u.uid=0),
	; 'isdir' does not bother checking. The current i-node
	;  is not disturbed.			
	;		
	; INPUTS ->
	;    r1 - contains the i-number whose i-node is being checked.
	;    u.uid - user id
	; OUTPUTS ->
	;    r1 - contains current i-number upon exit
	;    	 (current i-node back in core) 
	;	
	; ((AX = R1))
	;
        ; ((Modified registers: eAX, eDX, eBX, eCX, eSI, eDI, eBP))  
	;

	; / if the i-node whose i-number is in r1 is a directory 
	; / there is an error unless super user made the call
	
	cmp	byte [u.uid], 0 
		; tstb u.uid / super user
	jna	short isdir1
		; beq 1f / yes, don't care
	push	word [ii]
		; mov ii,-(sp) / put current i-number on stack
	call	iget
		; jsr r0,iget / get i-node into core (i-number in r1)
	test 	word [i.flgs], 4000h ; Bit 14 : Directory flag
		; bit $40000,i.flgs / is it a directory
	;jnz	error
		; bne error9 / yes, error
	jz	short isdir0
	mov 	dword [u.error], ERR_NOT_FILE  ; 11 ; ERR_DIR_ACCESS 
				; 'permission denied !' error
	; pop	ax
	jmp	error	
isdir0:	
	pop	ax
		; mov (sp)+,r1 / no, put current i-number in r1 (ii)
	call	iget
		; jsr r0,iget / get it back in
isdir1: ; 1:
	retn
		; rts r0

sysunlink:
	; 04/12/2015 (14 byte file names)
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/06/2013 (Retro UNIX 8086 v1)
	;
	; 'sysunlink' removes the entry for the file pointed to by
	; name from its directory. If this entry was the last link
	; to the file, the contents of the file are freed and the
	; file is destroyed. If, however, the file was open in any
	; process, the actual destruction is delayed until it is 
	; closed, even though the directory entry has disappeared.
	; 
	; The error bit (e-bit) is set to indicate that the file	
	; does not exist or that its directory can not be written.
	; Write permission is not required on the file itself.
	; It is also illegal to unlink a directory (except for
	; the superuser).
	;
	; Calling sequence:
	;	sysunlink; name
	; Arguments:
	;	name - name of directory entry to be removed 
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification:
	;	 The user/application program puts address of the name
	;        in BX register as 'sysunlink' system call argument.

	; / name - remove link name
	mov	[u.namep], ebx
		;jsr r0,arg; u.namep / u.namep points to name
	call	namei
		; jsr r0,namei / find the i-number associated 
			     ; / with the path name
	;jc	error
		; br error9 / not found
	jnc	short sysunlink1
	; 'file not found !' error
	mov	dword [u.error], ERR_FILE_NOT_FOUND ; 12
	jmp	error
sysunlink1:
	push	ax
		; mov r1,-(sp) / put its i-number on the stack
	call	isdir
		; jsr r0,isdir / is it a directory
	xor 	ax, ax
	mov	[u.dirbuf], ax ; 0
		; clr u.dirbuf / no, clear the location that will
			   ; / get written into the i-number portion
			 ; / of the entry
	sub	dword [u.off], 16 ; 04/12/2015 (10 -> 16) 
		; sub $10.,u.off / move u.off back 1 directory entry
	call	wdir
		; jsr r0,wdir / free the directory entry
	pop	ax
		; mov (sp)+,r1 / get i-number back
	call	iget
		; jsr r0,iget / get i-node
	call	setimod
		; jsr r0,setimod / set modified flag
	dec	byte [i.nlks]
		; decb i.nlks / decrement the number of links
	jnz	sysret
		; bgt sysret9 / if this was not the last link
			    ; / to file return
	; AX = r1 = i-number
	call	anyi
		; jsr r0,anyi / if it was, see if anyone has it open.
			 ; / Then free contents of file and destroy it.
	jmp	sysret
		; br sysret9

mkdir:
	; 04/12/2015 (14 byte directory names)
	; 12/10/2015
	; 17/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 29/04/2013 - 01/08/2013 (Retro UNIX 8086 v1)
	;
	; 'mkdir' makes a directory entry from the name pointed to
	; by u.namep into the current directory.
	;
	; INPUTS ->
	;    u.namep - points to a file name 
	;	           that is about to be a directory entry.
	;    ii - current directory's i-number.	
	; OUTPUTS ->
	;    u.dirbuf+2 - u.dirbuf+10 - contains file name. 
	;    u.off - points to entry to be filled 
	;	     in the current directory		
	;    u.base - points to start of u.dirbuf.
	;    r1 - contains i-number of current directory 
	;	
	; ((AX = R1)) output
	;
	;    (Retro UNIX Prototype : 11/11/2012, UNIXCOPY.ASM)
        ;    ((Modified registers: eAX, eDX, eBX, eCX, eSI, eDI, eBP))  
	;

	; 17/06/2015 - 32 bit modifications (Retro UNIX 386 v1)
	xor 	eax, eax
	mov     edi, u.dirbuf+2
	mov	esi, edi
	stosd
	stosd
	; 04/12/2015 (14 byte directory names)
	stosd
	stosw
		; jsr r0,copyz; u.dirbuf+2; u.dirbuf+10. / clear this
	mov	edi, esi ; offset to u.dirbuf
	; 12/10/2015 ([u.namep] -> ebp)
	;mov 	ebp, [u.namep]
	call	trans_addr_nmbp ; convert virtual address to physical
		; esi = physical address (page start + offset)
		; ecx = byte count in the page (1 - 4096)
	; edi = offset to u.dirbuf (edi is not modified in trans_addr_nm)
		; mov u.namep,r2 / r2 points to name of directory entry
		; mov $u.dirbuf+2,r3 / r3 points to u.dirbuf+2
mkdir_1: ; 1: 
	inc	ebp ; 12/10/2015
	;
	; / put characters in the directory name in u.dirbuf+2 - u.dirbuf+10
	 ; 01/08/2013
	lodsb
		; movb (r2)+,r1 / move character in name to r1
	and 	al, al
	jz 	short mkdir_3 	  
		; beq 1f / if null, done
	cmp	al, '/'
		; cmp r1,$'/ / is it a "/"?
	je	short mkdir_err
	;je	error
		; beq error9 / yes, error
	; 12/10/2015
	dec	cx
	jnz	short mkdir_2
	; 12/10/2015 ([u.namep] -> ebp)
	call	trans_addr_nm ; convert virtual address to physical
		; esi = physical address (page start + offset)
		; ecx = byte count in the page
	; edi = offset to u.dirbuf (edi is not modified in trans_addr_nm)
mkdir_2:
	cmp     edi, u.dirbuf+16 ; ; 04/12/2015 (10 -> 16) 
		; cmp r3,$u.dirbuf+10. / have we reached the last slot for
				     ; / a char?
	je	short mkdir_1
		; beq 1b / yes, go back
	stosb
		; movb r1,(r3)+ / no, put the char in the u.dirbuf
	jmp 	short mkdir_1
		; br 1b / get next char
mkdir_err:
	; 17/06/2015
	mov	dword [u.error], ERR_NOT_DIR ; 'not a valid directory !'
	jmp	error

mkdir_3: ; 1:
	mov	eax, [u.dirp]
	mov	[u.off], eax
		; mov u.dirp,u.off / pointer to empty current directory
				 ; / slot to u.off
wdir: ; 29/04/2013
        mov     dword [u.base], u.dirbuf
		; mov $u.dirbuf,u.base / u.base points to created file name
        mov     dword [u.count], 16 ; 04/12/2015 (10 -> 16) 
		; mov $10.,u.count / u.count = 10
	mov	ax, [ii] 
		; mov ii,r1 / r1 has i-number of current directory
	mov	dl, 1 ; owner flag mask ; RETRO UNIX 8086 v1 modification !
	call 	access
		; jsr r0,access; 1 / get i-node and set its file up 
				 ; / for writing
	; AX = i-number of current directory
	; 01/08/2013
	inc     byte [u.kcall] ; the caller is 'mkdir' sign	
	call	writei
		; jsr r0,writei / write into directory
	retn	
		; rts r0

sysexec:
	; 23/10/2015
	; 19/10/2015
	; 18/10/2015
	; 10/10/2015
	; 26/08/2015
	; 05/08/2015
	; 29/07/2015
	; 25/07/2015
	; 24/07/2015
	; 21/07/2015
	; 20/07/2015
	; 02/07/2015
	; 01/07/2015
	; 25/06/2015
	; 24/06/2015
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 03/06/2013 - 06/12/2013 (Retro UNIX 8086 v1)
	;
	; 'sysexec' initiates execution of a file whose path name if
	; pointed to by 'name' in the sysexec call. 
	; 'sysexec' performs the following operations:
	;    1. obtains i-number of file to be executed via 'namei'.
	;    2. obtains i-node of file to be exceuted via 'iget'.
	;    3. sets trap vectors to system routines.
	;    4. loads arguments to be passed to executing file into
	;	highest locations of user's core
	;    5. puts pointers to arguments in locations immediately
	;	following arguments.
	;    6.	saves number of arguments in next location.
	;    7. intializes user's stack area so that all registers
	;	will be zeroed and the PS is cleared and the PC set
	;	to core when 'sysret' restores registers 
	;	and does an rti.
	;    8. inializes u.r0 and u.sp
	;    9. zeros user's core down to u.r0
	;   10.	reads executable file from storage device into core
	;	starting at location 'core'.
	;   11.	sets u.break to point to end of user's code with
	;	data area appended.
	;   12.	calls 'sysret' which returns control at location
	;	'core' via 'rti' instruction. 		  		
	;
	; Calling sequence:
	;	sysexec; namep; argp
	; Arguments:
	;	namep - points to pathname of file to be executed
	;	argp  - address of table of argument pointers
	;	argp1... argpn - table of argument pointers
	;	argp1:<...0> ... argpn:<...0> - argument strings
	; Inputs: (arguments)
	; Outputs: -	
	; ...............................................................
	;
	; Retro UNIX 386 v1 modification: 
	;	User application runs in it's own virtual space 
	;	which is izolated from kernel memory (and other
	;	memory pages) via 80386	paging in ring 3 
	;	privilige mode. Virtual start address is always 0.
	;	User's core memory starts at linear address 400000h
	;	(the end of the 1st 4MB).
	;
	; Retro UNIX 8086 v1 modification: 
	;	user/application segment and system/kernel segment
	;	are different and sysenter/sysret/sysrele routines
	;	are different (user's registers are saved to 
	;	and then restored from system's stack.)
	;
	;	NOTE: Retro UNIX 8086 v1 'arg2' routine gets these
	;	      arguments which were in these registers;
	;	      but, it returns by putting the 1st argument
	;	      in 'u.namep' and the 2nd argument
	;	      on top of stack. (1st argument is offset of the
	;	      file/path name in the user's program segment.)		 	
	
	;call	arg2
	; * name - 'u.namep' points to address of file/path name
	;          in the user's program segment ('u.segmnt')
	;          with offset in BX register (as sysopen argument 1).
	; * argp - sysexec argument 2 is in CX register 
	;          which is on top of stack.
	;
		; jsr r0,arg2 / arg0 in u.namep,arg1 on top of stack

	; 23/06/2015 (32 bit modifications)

	mov	[u.namep], ebx ; argument 1
        ; 18/10/2015
	mov     [argv], ecx  ; * ; argument 2
	call	namei
		; jsr r0,namei / namei returns i-number of file 
			     ; / named in sysexec call in r1
	;jc	error
		; br error9
	jnc	short sysexec_0
	;
	; 'file not found !' error
	mov	dword [u.error], ERR_FILE_NOT_FOUND
	jmp	error 
sysexec_not_exf:
	; 'not executable file !' error
	mov	dword [u.error], ERR_NOT_EXECUTABLE
	jmp	error 
sysexec_0:
	call	iget
		; jsr r0,iget / get i-node for file to be executed
        test    word [i.flgs], 10h
		; bit $20,i.flgs / is file executable
	jz	short sysexec_not_exf
	;jz	error
		; beq error9
	;;
	call	iopen
		; jsr r0,iopen / gets i-node for file with i-number
			     ; / given in r1 (opens file)
	; AX = i-number of the file
	test	word [i.flgs], 20h
		; bit $40,i.flgs / test user id on execution bit
	jz	short sysexec_1
		; beq 1f
	cmp 	byte [u.uid], 0 ; 02/08/2013
		; tstb u.uid / test user id
	jna	short sysexec_1
		; beq 1f / super user
	mov	cl, [i.uid]
	mov	[u.uid], cl ; 02/08/2013
		; movb i.uid,u.uid / put user id of owner of file
				 ; / as process user id
sysexec_1:
	; 18/10/2215
	; 10/10/2015
	; 24/07/2015
	; 21/07/2015
	; 25/06/2015
	; 24/06/2015
        ; Moving arguments to the end of [u.upage]
	; (by regarding page borders in user's memory space)
	;
	; 10/10/2015
	; 21/07/2015
	mov	ebp, esp ; (**)
	; 18/10/2015
	mov 	edi, ebp
	mov 	ecx, MAX_ARG_LEN ; 256
	;sub	edi, MAX_ARG_LEN ; 256
	sub	edi, ecx
	mov	esp, edi
	xor	eax, eax
	mov 	[u.nread], eax ; 0
	dec	ecx ; 256 - 1
	mov 	[u.count], ecx ; MAX_ARG_LEN - 1 ; 255
	;mov 	dword [u.count], MAX_ARG_LEN - 1 ; 255
sysexec_2:
	mov	esi, [argv] ; 18/10/2015 
	call	get_argp
	mov	ecx, 4 ; mov ecx, 4
sysexec_3:
	and	eax, eax
	jz	short sysexec_6
	; 18/10/2015
	add	[argv], ecx ; 4
	inc	word [argc]
	;
	mov	[u.base], eax
 	; 23/10/2015
	mov	word [u.pcount], 0
sysexec_4:
	call	cpass ; get a character from user's core memory
        jnz      short sysexec_5
		; (max. 255 chars + null)
	; 18/10/2015
	sub 	al, al
	stosb
	inc	dword [u.nread]
	jmp	short sysexec_6
sysexec_5:
	stosb
	and 	al, al
	jnz	short sysexec_4
	mov	ecx, 4
	cmp	[ncount], ecx ; 4
	jb	short sysexec_2
	mov	esi, [nbase]
	add	[nbase], ecx ; 4	
	sub	[ncount], cx 
	mov	eax, [esi]
	jmp	short sysexec_3
sysexec_6:
	; 18/10/2015
	; argument list transfer from user's core memory to
	; kernel stack frame is OK here.
	; [u.nread] = ; argument list length
	;mov	[argv], esp ; start address of argument list 	
	;
	; 18/10/2015
	; 24/07/2015
        ; 21/07/2015
	; 02/07/2015
	; 25/06/2015
	; 24/06/2015
	; 23/06/2015
	;
	mov	ebx, [u.ppgdir] ; parent's page directory
	and 	ebx, ebx  ; /etc/init ? (u.ppgdir = 0)	
	jz	short sysexec_7
	mov	eax, [u.pgdir] ; physical address of page directory
	call	deallocate_page_dir
sysexec_7:
	call	make_page_dir
	;jc	short sysexec_14
	jc	panic  ; allocation error 
		       ; after a deallocation would be nonsence !?
	; 24/07/2015
	; map kernel pages (1st 4MB) to PDE 0
	;     of the user's page directory
	;     (It is needed for interrupts!)
	; 18/10/2015
	mov	edx, [k_page_dir] ; Kernel's page directory
	mov	eax, [edx] ; physical address of
			   ; kernel's first page table (1st 4 MB)
			   ; (PDE 0 of kernel's page directory)
	mov 	edx, [u.pgdir]
	mov	[edx], eax ; PDE 0 (1st 4MB)
	;
	; 20/07/2015
	mov	ebx, CORE ; start address = 0 (virtual) + CORE
	; 18/10/2015
	mov	esi, pcore ; physical start address
sysexec_8:	
	mov	ecx, PDE_A_USER + PDE_A_WRITE + PDE_A_PRESENT
	call	make_page_table
	jc	panic
	;mov	ecx, PTE_A_USER + PTE_A_WRITE + PTE_A_PRESENT
	call	make_page ; make new page, clear and set the pte 
	jc	panic
	;
	mov	[esi], eax ; 24/06/2015
	; ebx = virtual address (24/07/2015)
	call 	add_to_swap_queue
	; 18/10/2015
	cmp	esi, ecore ; user's stack (last) page ?
	je	short sysexec_9 ; yes
	mov	esi, ecore  ; physical address of the last page 
	; 20/07/2015
	mov	ebx, (ECORE - PAGE_SIZE) + CORE
	; ebx = virtual end address + segment base address - 4K
        jmp     short sysexec_8

sysexec_9:
	; 18/10/2015
	; 26/08/2015
	; 25/06/2015
	; move arguments from kernel stack to [ecore]
	; (argument list/line will be copied from kernel stack
	; frame to the last (stack) page of user's core memory)
	; 18/10/2015
	mov	edi, [ecore]
	add	edi, PAGE_SIZE
	movzx	eax, word [argc]
	or	eax, eax
	jnz	short sysexec_10
	mov 	ebx, edi
	sub	ebx, 4 
	mov	[ebx], eax ; 0
	jmp 	short sysexec_13
sysexec_10:
	mov	ecx, [u.nread]
	;mov 	esi, [argv}
	mov	esi, esp ; start address of argument list
	sub	edi, ecx ; page end address - argument list length
	mov	edx, eax
	inc	dl ; argument count + 1 for argc value  
	shl 	dl, 2  ; 4 * (argument count + 1)
	mov	ebx, edi
	and	bl, 0FCh ; 32 bit (dword) alignment
	sub 	ebx, edx
	mov	edx, edi
	rep	movsb
	mov 	esi, edx
	mov 	edi, ebx
	mov	edx, ECORE - PAGE_SIZE ; virtual addr. of the last page
	sub 	edx, [ecore] ; difference (virtual - physical) 
	stosd	; eax = argument count	
sysexec_11:
	mov	eax, esi
	add	eax, edx
	stosd  ; eax = virtual address
	dec	byte [argc]
	jz	short sysexec_13
sysexec_12:
	lodsb
	and	al, al
	jnz	short sysexec_12
	jmp	short sysexec_11
	;
	; 1:
		; mov (sp)+,r5 / r5 now contains address of list of 
			     ; / pointers to arguments to be passed
		; mov $1,u.quit / u.quit determines handling of quits;
			      ; / u.quit = 1 take quit
		; mov $1,u.intr / u.intr determines handling of 
			     ; / interrupts; u.intr = 1 take interrupt
		; mov $rtssym,30 / emt trap vector set to take 
			       ; / system routine
		; mov $fpsym,*10 / reserved instruction trap vector 
			       ; / set to take system routine
		; mov $sstack,sp / stack space used during swapping
		; mov r5,-(sp) / save arguments pointer on stack
		; mov $ecore,r5 / r5 has end of core
		; mov $core,r4 / r4 has start of users core
		; mov r4,u.base / u.base has start of users core
		; mov (sp),r2 / move arguments list pointer into r2
	; 1:
		; tst (r2)+ / argument char = "nul"
		; bne 1b
		; tst -(r2) / decrement r2 by 2; r2 has addr of 
			  ; / end of argument pointer list
	; 1:
	     ; / move arguments to bottom of users core
		; mov -(r2),r3 / (r3) last non zero argument ptr
		; cmp r2,(sp) / is r2 = beginning of argument
			    ; / ptr list
		; blo 1f / branch to 1f when all arguments
		       ; / are moved
		; mov -(r2),r3 / (r3) last non zero argument ptr
	; 2:
		; tstb (r3)+
		; bne 2b / scan argument for \0 (nul)

	; 2:
		; movb -(r3),-(r5) / move argument char 
				 ; / by char starting at "ecore"
		; cmp r3,(r2) / moved all characters in 
			    ; / this argument
		; bhi 2b / branch 2b if not
		; mov r5,(r4)+ / move r5 into top of users core;
			     ; / r5 has pointer to nth arg
		; br 1b / string
	; 1:
		; clrb -(r5)
		; bic $1,r5 / make r5 even, r5 points to 
			; / last word of argument strings
		; mov $core,r2
	
	; 1: / move argument pointers into core following 
	      ; / argument strings
		; cmp r2,r4
		; bhis 1f / branch to 1f when all pointers
			; / are moved
		; mov (r2)+,-(r5)
		; br 1b
	; 1:
		; sub $core,r4 / gives number of arguments *2
		; asr r4 / divide r4 by 2 to calculate 
		       ; / the number of args stored
		; mov r4,-(r5) / save number of arguments ahead
			     ; / of the argument pointers
sysexec_13:
	; 19/10/2015
	; 18/10/2015
	; 29/07/2015
	; 25/07/2015
	; 24/07/2015
	; 20/07/2015
	; 25/06/2015
	; 24/06/2015
	; 23/06/2015
	;
	; moving arguments to [ecore] is OK here..
	; 18/10/2015
	mov 	esp, ebp ; (**) restore kernel stack pointer
	; ebx = beginning addres of argument list pointers
	;	in user's stack
	; 19/10/2015
	sub 	ebx, [ecore]
	add     ebx, (ECORE - PAGE_SIZE)
			; end of core - 4096 (last page)
			; (virtual address)
	mov	[argv], ebx
	mov	[u.break], ebx ; available user memory
	;
	sub	eax, eax
	mov	dword [u.count], 32 ; Executable file header size
		; mov $14,u.count
	mov	dword [u.fofp], u.off
		; mov $u.off,u.fofp
	mov	[u.off], eax ; 0
		; clr u.off / set offset in file to be read to zero
	; 25/07/2015
	mov	[u.base], eax ; 0, start of user's core (virtual)
	; 25/06/2015 
	mov	ax, [ii]
	; AX = i-number of the executable file
	call	readi
		; jsr r0,readi / read in first six words of 
			; / user's file, starting at $core
		; mov sp,r5 / put users stack address in r5
		; sub $core+40.,r5 / subtract $core +40, 
				; / from r5 (leaves number of words
				; / less 26 available for
			     	; / program in user core
		; mov r5,u.count /
	; 25/06/2015
	mov	ecx, [u.break] ; top of user's stack (physical addr.)
	mov	[u.count], ecx ; save for overrun check
	;
	mov	ecx, [u.nread]
	mov	[u.break], ecx ; virtual address (offset from start)
	cmp	cl, 32
        jne     short sysexec_15
	;:
	; 25/06/2015
	; Retro UNIX 386 v1 (32 bit) executable file header format
	; 18/10/2015
	mov	esi, [pcore] ; start address of user's core memory 
		             ; (phys. start addr. of the exec. file)
	lodsd
	cmp	ax, 1EEBh ; EBH, 1Eh -> jump to +32
	jne	short sysexec_15
		; cmp core,$405 / br .+14 is first instruction 
			      ; / if file is standard a.out format
		; bne 1f / branch, if not standard format
	lodsd
	mov	ecx, eax ; text (code) section size
	lodsd
	add	ecx, eax ; + data section size (initialized data)
		; mov core+2,r5 / put 2nd word of users program in r5;
		              ; / number of bytes in program text	
		; sub $14,r5 / subtract 12
	mov	ebx, ecx
	;
	; 25/06/2015
	; NOTE: These are for next versions of Retro UNIX 386
	;	and SINGLIX operating systems (as code template).
	;	Current Retro UNIX 386 v1 files can be max. 64KB
	;	due to RUFS (floppy disk file system) restriction...
	;	Overrun is not possible for current version. 	
	;
	lodsd	
	add	ebx, eax ; + bss section size (for overrun checking)
	cmp	ebx, [u.count]
	ja	short sysexec_14  ; program overruns stack !
	;
	; 24/07/2015
	; add bss section size to [u.break]
	add 	[u.break], eax
	;
	sub	ecx, 32  ; header size (already loaded)
	;cmp	ecx, [u.count]
	;jnb	short sysexec_16
		; cmp r5,u.count /
		; bgt 1f / branch if r5 greater than u.count
	mov	[u.count], ecx ; required read count
		; mov r5,u.count
	;
	jmp	short sysexec_16
	;
sysexec_14:
	; 23/06/2015
	; insufficient (out of) memory
	mov	dword [u.error], ERR_MINOR_IM ; 1
	jmp	error
	;
sysexec_15:
	; 25/06/2015
        movzx   edx, word [i.size] ; file size
	sub	edx, ecx ; file size - loaded bytes
	jna	short sysexec_17 ; no need to next read
	add	ecx, edx ; [i.size]
	cmp	ecx, [u.count] ; overrun check (!)
	ja	short sysexec_14
	mov	[u.count], edx
sysexec_16:
	mov	ax, [ii] ; i-number
	call	readi
		; add core+10,u.nread / add size of user data area 
		                    ; / to u.nread
		; br 2f
	; 1:
		; jsr r0,readi / read in rest of file
	; 2:
	mov	ecx, [u.nread]
	add	[u.break], ecx
		; mov u.nread,u.break / set users program break to end of 
				    ; / user code
		; add $core+14,u.break / plus data area
sysexec_17: ; 20/07/2015
	;mov	ax, [ii] ;rgc i-number
	call	iclose
		; jsr r0,iclose / does nothing
        xor     eax, eax
	inc	al
	mov	[u.intr], ax ; 1 (interrupt/time-out is enabled)
	mov	[u.quit], ax ; 1 ('crtl+brk' signal is enabled) 
	; 02/07/2015
        cmp	dword [u.ppgdir], 0  ; is the caller sys_init (kernel) ?
	ja	short sysexec_18 ; no, the caller is user process
	; If the caller is kernel (sys_init), 'sysexec' will come here
	mov	edx, [k_page_dir] ; kernel's page directory
	mov	[u.ppgdir], edx ; next time 'sysexec' must not come here 
sysexec_18:
	; 18/10/2015
	; 05/08/2015
	; 29/07/2015
	mov	ebp, [argv] ; user's stack pointer must point to argument
			    ; list pointers (argument count)
	cli
        mov     esp, [tss.esp0]  ; ring 0 (kernel) stack pointer
	;mov   	esp, [u.sp] ; Restore Kernel stack
			    ; for this process	 
	;add	esp, 20 ; --> EIP, CS, EFLAGS, ESP, SS
	;xor	eax, eax ; 0
	dec	al ; eax = 0
	mov	dx, UDATA
	push	dx  ; user's stack segment
	push	ebp ; user's stack pointer
		    ; (points to number of arguments)
	sti
	pushfd	; EFLAGS
		; Set IF for enabling interrupts in user mode	
	;or	dword [esp], 200h 
	;
	;mov	bx, UCODE
	;push	bx ; user's code segment
	push	UCODE
	;push	0
	push	eax ; EIP (=0) - start address -	
		; clr -(r5) / popped into ps when rti in 
			  ; / sysrele is executed
		; mov $core,-(r5) / popped into pc when rti 
		                ; / in sysrele is executed
		;mov r5,0f / load second copyz argument
		;tst -(r5) / decrement r5
	mov	[u.sp], esp ; 29/07/2015
	; 05/08/2015
	; Remedy of a General Protection Fault during 'iretd' is here !
	; ('push dx' would cause to general protection fault, 
	; after 'pop ds' etc.)
	;
	;; push dx ; ds (UDATA)
	;; push dx ; es (UDATA)
	;; push dx ; fs (UDATA)
	;; push dx ; gs (UDATA)
	;
	; This is a trick to prevent general protection fault
	; during 'iretd' intruction at the end of 'sysrele' (in u1.s):
	mov 	es, dx ; UDATA
	push 	es ; ds (UDATA)
	push 	es ; es (UDATA)
	push 	es ; fs (UDATA)
	push	es ; gs (UDATA)
	mov	dx, KDATA
	mov	es, dx
	;
	;; pushad simulation
	mov	ebp, esp ; esp before pushad
	push	eax ; eax (0)
	push	eax ; ecx (0)
	push	eax ; edx (0)
	push	eax ; ebx (0)
	push	ebp ; esp before pushad
	push	eax ; ebp (0)
	push	eax ; esi (0)		
	push	eax ; edi (0)	
	;
	mov	[u.r0], eax ; eax = 0
	mov	[u.usp], esp
		; mov r5,u.r0 /
		; sub $16.,r5 / skip 8 words
		; mov r5,u.sp / assign user stack pointer value, 
		;             / effectively zeroes all regs
			    ; / when sysrele is executed
		; jsr r0,copyz; core; 0:0 / zero user's core
		; clr u.break
		; mov r5,sp / point sp to user's stack
	;
	jmp	sysret0
	;jmp	sysret
		; br sysret3 / return to core image at $core

get_argp:
	; 18/10/2015 (nbase, ncount)
	; 21/07/2015
	; 24/06/2015 (Retro UNIX 386 v1)
	; Get (virtual) address of argument from user's core memory
	;
	; INPUT:
	;	esi = virtual address of argument pointer
	; OUTPUT:
	;	eax = virtual address of argument
	;
	; Modified registers: EAX, EBX, ECX, EDX, ESI 
	;
 	cmp     dword [u.ppgdir], 0 ; /etc/init ?
				    ; (the caller is kernel)
        jna     short get_argpk 
	;
     	mov	ebx, esi
	call	get_physical_addr ; get physical address
        jc      get_argp_err
	mov 	[nbase], eax ; physical address	
	mov	[ncount], cx ; remain byte count in page (1-4096)
	mov	eax, 4 ; 21/07/2015
	cmp	cx, ax ; 4
	jnb	short get_argp2
	mov	ebx, esi
	add	ebx, ecx
	call	get_physical_addr ; get physical address
	jc	short get_argp_err
	;push	esi
	mov	esi, eax
	xchg	cx, [ncount]
	xchg	esi, [nbase]
	mov	ch, 4
	sub	ch, cl
get_argp0:
	lodsb
	push	ax
	dec	cl
        jnz     short get_argp0
	mov	esi, [nbase]
	; 21/07/2015
	movzx	eax, ch
	add	[nbase], eax
	sub	[ncount], ax
get_argp1:
	lodsb
	dec	ch
        jz      short get_argp3
        push	ax
	jmp     short get_argp1
get_argpk:
	; Argument is in kernel's memory space
	mov	word [ncount], PAGE_SIZE ; 4096
	mov	[nbase], esi
	add	dword [nbase], 4
	mov	eax, [esi] ; virtual addr. = physcal addr.
	retn
get_argp2:
	; 21/07/2015
	;mov	eax, 4
	mov 	edx, [nbase] ; 18/10/2015
	add	[nbase], eax
	sub	[ncount], ax
	;
	mov	eax, [edx]
	retn
get_argp_err:
	mov	[u.error], eax
	jmp	error
get_argp3:
	mov	cl, 3
get_argp4:
	shl	eax, 8
	pop	dx
	mov 	al, dl
        loop    get_argp4
	;pop	esi
	retn	

sysfstat: 
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/06/2013 (Retro UNIX 8086 v1)
	;
	; 'sysfstat' is identical to 'sysstat' except that it operates
	; on open files instead of files given by name. It puts the
	; buffer address on the stack, gets the i-number and
	; checks to see if the file is open for reading or writing.
	; If the file is open for writing (i-number is negative)
	; the i-number is set positive and a branch into 'sysstat'
	; is made.	
	;
	; Calling sequence:
	;	sysfstat; buf
	; Arguments:
	;	buf - buffer address
	;
	; Inputs: *u.r0 - file descriptor
	; Outputs: buffer is loaded with file information
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification:
	;       'sysfstat' system call has two arguments; so,
	;	* 1st argument, file descriptor is in BX register
	;	* 2nd argument, buf is pointed to by CX register

	; / set status of open file
		; jsr r0,arg; u.off / put buffer address in u.off
	push	ecx
		; mov u.off,-(sp) / put buffer address on the stack
		; mov *u.r0,r1 / put file descriptor in r1
		; jsr r0,getf / get the files i-number
	; BX = file descriptor (file number)
	call	getf1
	and	ax, ax ; i-number of the file
		; tst	r1 / is it 0?
	;jz	error
		; beq error3 / yes, error
	jnz	short sysfstat1
	mov	dword [u.error], ERR_FILE_NOT_OPEN  ; 'file not open !'
	jmp	error
sysfstat1:
	cmp	ah, 80h
        jb      short sysstat1
		; bgt 1f / if i-number is negative (open for writing)
	neg	ax
		; neg r1 / make it positive, then branch
	jmp	short sysstat1
		; br 1f / to 1f
sysstat:
	; 18/10/2015
	; 07/10/2015
	; 02/09/2015
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/06/2013 (Retro UNIX 8086 v1)
	;
	; 'sysstat' gets the status of a file. Its arguments are the
	; name of the file and buffer address. The buffer is 34 bytes
	; long and information about the file placed in it.	
	; sysstat calls 'namei' to get the i-number of the file.
	; Then 'iget' is called to get i-node in core. The buffer
	; is then loaded and the results are given in the UNIX
	; Programmers Manual sysstat (II).	
	;
	; Calling sequence:
	;	sysstat; name; buf
	; Arguments:
	;	name - points to the name of the file
	;	buf - address of a 34 bytes buffer
	; Inputs: -
	; Outputs: buffer is loaded with file information
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysstat' system call has two arguments; so,
	;	Retro UNIX 8086 v1 argument transfer method 2 is used
	;	to get sysstat system call arguments from the user;
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, buf is pointed to by CX register
	;
	;	NOTE: Retro UNIX 8086 v1 'arg2' routine gets these
	;	      arguments which were in these registers;
	;	      but, it returns by putting the 1st argument
	;	      in 'u.namep' and the 2nd argument
	;	      on top of stack. (1st argument is offset of the
	;	      file/path name in the user's program segment.)		 	
	
	; / ; name of file; buffer - get files status
		; jsr r0,arg2 / get the 2 arguments
	mov	[u.namep], ebx
	push	ecx
	call	namei
		; jsr r0,namei / get the i-number for the file
	;jc	error
		; br error3 / no such file, error
	jnc	short sysstat1
	; pop 	ecx
sysstat_err0:
	; 'file not found !' error
	mov	dword [u.error], ERR_FILE_NOT_FOUND ; 12
	jmp	error

statx: db 0

sysstat1: ; 1:
	call	iget
		; jsr r0,iget / get the i-node into core
	; 07/10/2015 (ax = [ii], inode number)
	; 02/09/2015
	pop	dword [u.base]
		; mov (sp)+,r3 / move u.off to r3 (points to buffer)
	call	sysstat_gpa ; get physical address
	jnc 	short sysstat2
sysstat_err1:
	mov	dword [u.error], eax ; error code
	jmp	error
sysstat2:
	mov 	al, [ii] ; 07/10/2015 (result of 'iget' call, above)
	stosb
	inc 	dword [u.base]
	dec 	cx
	jnz	short sysstat3
	call	sysstat_gpa
	;jc	short sysstat_err1
sysstat3:
	mov 	al, [ii+1] ; 07/10/2015 (result of 'iget' call, above)
	stosb
		; mov r1,(r3)+ / put i-number in 1st word of buffer
	inc 	dword [u.base]
	;dec 	word [u.pcount]
	dec	cx
	jnz	short sysstat4
	call	sysstat_gpa
	;jc	short sysstat_err1	
sysstat4:
	mov	esi, inode
		; mov $inode,r2 / r2 points to i-node
sysstat5: ; 1:
	movsb
		; mov (r2)+,(r3)+ / move rest of i-node to buffer
	inc 	dword [u.base]
	;dec 	word [u.pcount]
	dec	cx
	jnz	short sysstat6
	call	sysstat_gpa
	;jc	short sysstat_err1
sysstat6:		
	cmp	esi, inode + 32
		; cmp r2,$inode+32 / done?
	jne	short sysstat5
		; bne 1b / no, go back
	jmp	sysret
		; br sysret3 / return through sysret
	;
sysstat_gpa: ; get physical address of file status buffer
	; 02/09/2015
	mov 	ebx, [u.base]
	; 07/10/2015
	call	get_physical_addr ; get physical address
	;jc	short sysstat_gpa1
	jc	short sysstat_err1
	; 18/10/2015
	mov	edi, eax ; physical address
	;mov	[u.pcount], cx ; remain bytes in page
;sysstat_gpa1:
	retn

fclose:
	; 18/06/2015 (Retro UNIX 386 v1 - Beginning)
	;            (32 bit offset pointer modification)
	; 19/04/2013 - 12/01/2014 (Retro UNIX 8086 v1)
	;
	; Given the file descriptor (index to the u.fp list)
	; 'fclose' first gets the i-number of the file via 'getf'.
	; If i-node is active (i-number > 0) the entry in 
	; u.fp list is cleared. If all the processes that opened
	; that file close it, then fsp etry is freed and the file
	; is closed. If not a return is taken. 
	; If the file has been deleted while open, 'anyi' is called
	; to see anyone else has it open, i.e., see if it is appears
	; in another entry in the fsp table. Upon return from 'anyi'
	; a check is made to see if the file is special.	
	;
	; INPUTS ->
	;    r1 - contains the file descriptor (value=0,1,2...)
	;    u.fp - list of entries in the fsp table
	;    fsp - table of entries (4 words/entry) of open files.	 
	; OUTPUTS ->
	;    r1 - contains the same file descriptor
	;    r2 - contains i-number
	;
	; ((AX = R1))
	; ((Modified registers: eDX, eBX, eCX, eSI, eDI, eBP))
	;
	; Retro UNIX 8086 v1 modification : CF = 1
	;              if i-number of the file is 0. (error)  	
	;
	movzx	edx, ax ; **
	push	ax ; ***
		; mov r1,-(sp) / put r1 on the stack (it contains 
			     ; / the index to u.fp list)
	call	getf
		; jsr r0,getf / r1 contains i-number, 
			    ; / cdev has device =, u.fofp 
			    ; / points to 3rd word of fsp entry
	cmp	ax, 1 ; r1
		; tst r1 / is i-number 0?
	jb	short fclose_2
		; beq 1f / yes, i-node not active so return
		; tst (r0)+ / no, jump over error return
	mov	ebx, edx ; **
	mov 	dx, ax ; *
		; mov r1,r2 / move i-number to r2 ;*
		; mov (sp),r1 / restore value of r1 from the stack
			    ; / which is index to u.fp ; **
	mov	byte [ebx+u.fp], 0
		; clrb u.fp(r1) / clear that entry in the u.fp list
	mov	ebx, [u.fofp]
		; mov u.fofp,r1 / r1 points to 3rd word in fsp entry
fclose_0:
	dec	byte [ebx+4] ; 18/06/2015
		; decb 2(r1) / decrement the number of processes 
			   ; / that have opened the file
	jns	short fclose_2 ; jump if not negative (jump if bit 7 is 0)	 
		; bge 1f / if all processes haven't closed the file, return
	;
	push	dx ;*
		; mov r2,-(sp) / put r2 on the stack (i-number)
	xor	ax, ax ; 0
	mov	[ebx-4], ax ; 0
		; clr -4(r1) / clear 1st word of fsp entry
	mov	al, [ebx+5] ; 18/06/2015
		; tstb	3(r1) / has this file been deleted
	and	al, al
	jz	short fclose_1
		; beq 2f / no, branch
	mov	ax, dx ; *
		; mov r2,r1 / yes, put i-number back into r1
	; AX = inode number
	call	anyi
		; jsr r0,anyi / free all blocks related to i-number
			    ; / check if file appears in fsp again
fclose_1: ; 2:
	pop	ax ; *
		; mov (sp)+,r1 / put i-number back into r1
	call	iclose ; close if it is special file 
		; jsr r0,iclose / check to see if its a special file
fclose_2: ; 1:
	pop	ax ; ***
		; mov (sp)+,r1 / put index to u.fp back into r1
	retn
		; rts r0

getf:	; / get the device number and the i-number of an open file
	; 13/05/2015
	; 11/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/04/2013 - 18/11/2013 (Retro UNIX 8086 v1)
	;
	mov	ebx, eax
getf1: ;; Calling point from 'rw1' (23/05/2013)
	cmp	ebx, 10
		; cmp r1,$10. / user limited to 10 open files
        jnb	short getf2 ; 13/05/2015
	;jnb     error
		; bhis error3 / u.fp is table of users open files, 
			    ; / index in fsp table
	mov	bl, [ebx+u.fp]
		; movb	u.fp(r1),r1 / r1 contains number of entry 
		                  ; / in fsp table
	or	bl, bl
	jnz	short getf3
	;jz	short getf4
		; beq 1f / if its zero return
getf2:
	; 'File not open !' error (ax=0)
	sub	eax, eax
	retn
getf3:	
	; Retro UNIX 386 v1 modification ! (11/05/2015)
	;
	; 'fsp' table (10 bytes/entry)
	; bit 15				   bit 0
	; ---|-------------------------------------------
	; r/w|		i-number of open file
	; ---|-------------------------------------------
	;		   device number
	; -----------------------------------------------
	; offset pointer, r/w pointer to file (bit 0-15)
	; -----------------------------------------------
	; offset pointer, r/w pointer to file (bit 16-31)
	; ----------------------|------------------------
	;  flag that says file 	| number of processes
	;   has been deleted	| that have file open 
	; ----------------------|------------------------
	;
	mov	eax, 10
	mul	bl
	mov	ebx, fsp - 6 ; the 3rd word in the fsp entry
	add	ebx, eax
		; asl r1
		; asl r1 / multiply by 8 to get index into 
		       ; / fsp table entry
		; asl r1
		; add $fsp-4,r1 / r1 is pointing at the 3rd word 
			      ; / in the fsp entry
	mov	[u.fofp], ebx
		; mov r1,u.fofp / save address of 3rd word 
			      ; / in fsp entry in u.fofp
	dec	ebx
	dec	ebx
	mov	ax, [ebx]
	;mov	[cdev], al ; ;;Retro UNIX 8086 v1 ! 
	mov	[cdev], ax ; ;;in fact (!) 
			     ;;dev number is in 1 byte
		; mov -(r1),cdev / remove the device number  cdev
	dec	ebx
	dec	ebx
	mov	ax, [ebx]
		; mov -(r1),r1 / and the i-number  r1
getf4:	; 1:
	retn
		; rts r0

namei:
	; 04/12/2015 (14 byte file names)
	; 18/10/2015 (nbase, ncount)
	; 12/10/2015
	; 21/08/2015
	; 18/07/2015
	; 02/07/2015
	; 17/06/2015
	; 16/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 24/04/2013 - 31/07/2013 (Retro UNIX 8086 v1)
	;
	; 'namei' takes a file path name and returns i-number of
	; the file in the current directory or the root directory
	; (if the first character of the pathname is '/').	
	;
	; INPUTS ->
	;    u.namep - points to a file path name
	;    u.cdir - i-number of users directory
	;    u.cdev - device number on which user directory resides	
	; OUTPUTS ->
	;    r1 - i-number of file
	;    cdev
	;    u.dirbuf - points to directory entry where a match 
	;               occurs in the search for file path name.
	;	        If no match u.dirb points to the end of 
	;               the directory and r1 = i-number of the current
	;	        directory.	
	; ((AX = R1))
	;
	; (Retro UNIX Prototype : 07/10/2012 - 05/01/2013, UNIXCOPY.ASM)
        ; ((Modified registers: eDX, eBX, eCX, eSI, eDI, eBP))  
	;

	mov	ax, [u.cdir]
		; mov u.cdir,r1 / put the i-number of current directory
			      ; / in r1
	mov	dx, [u.cdrv]
	mov	[cdev], dx 	    ; NOTE: Retro UNIX 8086 v1 
				    ; device/drive number is in 1 byte, 
				    ; not in 1 word!
		; mov u.cdev,cdev / device number for users directory 
				; / into cdev
	; 12/10/2015
	; 16/06/2015 - 32 bit modifications (Retro UNIX 386 v1)
      	 ; convert virtual (pathname) addr to physical address
	call    trans_addr_nmbp ; 12/10/2015
		; esi = physical address of [u.namep]
		; ecx = byte count in the page
	cmp	byte [esi], '/'
		; cmpb *u.namep,$'/ / is first char in file name a /
	jne	short namei_1
		; bne 1f
	inc	dword [u.namep]
		; inc u.namep / go to next char
	dec	cx ; remain byte count in the page
	jnz	short namei_0
	; 12/10/2015
	call	trans_addr_nmbp ; convert virtual address to physical
		; esi = physical address (page start + offset)
		; ecx = byte count in the page
	dec	esi
namei_0:
	inc 	esi  ; go to next char
	mov	ax, [rootdir] ; 09/07/2013
		; mov rootdir,r1 / put i-number of rootdirectory in r1
	mov	byte [cdev], 0
		; clr cdev / clear device number
namei_1: ; 1:
	test	byte [esi], 0FFh
	jz	short getf4
	;jz      nig
		; tstb *u.namep / is the character in file name a nul
		; beq nig / yes, end of file name reached; 
			; / branch to "nig"
namei_2: ; 1:
	; 18/10/2015
	mov 	[nbase], esi
	mov 	[ncount], cx
	;
	;mov	dx, 2
	mov	dl, 2 ; user flag (read, non-owner)
	call	access
		; jsr r0,access; 2 / get i-node with i-number r1
	; 'access' will not return here if user has not "r" permission !
	test 	word [i.flgs], 4000h
		; bit $40000,i.flgs / directory i-node?
        jz      short namei_err
		; beq error3 / no, got an error
	; 16/06/2015 - 32 bit modifications (Retro UNIX 386 v1)
	xor	eax, eax
	mov	[u.off], eax ; 0
	mov	ax, [i.size]
	mov	[u.dirp], eax
		; mov i.size,u.dirp / put size of directory in u.dirp
		; clr u.off / u.off is file offset used by user
	mov	dword [u.fofp], u.off
		; mov $u.off,u.fofp / u.fofp is a pointer to 
				  ; / the offset portion of fsp entry
namei_3: ; 2:
	mov	dword [u.base], u.dirbuf
		; mov $u.dirbuf,u.base / u.dirbuf holds a file name 
				    ; / copied from a directory
	mov 	dword [u.count], 16 ; 04/12/2015 (10 -> 16) 	
 		; mov $10.,u.count / u.count is byte count 
				 ; / for reads and writes
	mov 	ax, [ii]
	; 31/07/2013 ('namei_r') - 16/06/2015 ('u.kcall')
 	inc     byte [u.kcall] ; the caller is 'namei' sign	
    	call	readi
		; jsr r0,readi / read 10. bytes of file 
		      ; with i-number (r1); i.e. read a directory entry
	mov 	ecx, [u.nread]
	or 	ecx, ecx
		; tst u.nread
	jz	short nib
		; ble nib / gives error return
	;
	mov 	bx, [u.dirbuf]
	and 	bx, bx       
		; tst u.dirbuf /
	jnz	short namei_4
		; bne 3f / branch when active directory entry 
		       ; / (i-node word in entry non zero)
	mov	eax, [u.off]
	sub	eax, 16 ; 04/12/2015 (10 -> 16) 
	mov	[u.dirp], eax
		; mov u.off,u.dirp
		; sub $10.,u.dirp
	jmp	short namei_3
		; br 2b

	; 18/07/2013
nib: 
	xor	eax, eax  ; xor ax, ax ; ax = 0 -> file not found 
	stc
nig:
	retn

namei_err:
	; 16/06/2015
	mov	dword [u.error], ERR_NOT_DIR ; 'not a directory !' error
	jmp	error

namei_4: ; 3:
	; 18/10/2015
	; 12/10/2015
	; 21/08/2015
	; 18/07/2015
	mov	ebp, [u.namep]
		; mov u.namep,r2 / u.namep points into a file name string
	mov 	edi, u.dirbuf + 2
		; mov $u.dirbuf+2,r3 / points to file name of directory entry
	; 18/10/2015
	mov	esi, [nbase]	
	mov	cx, [ncount]
	;
	and	cx, cx
	jnz	short namei_5	
	;
	call	trans_addr_nm ; convert virtual address to physical
		; esi = physical address (page start + offset)
		; ecx = byte count in the page
namei_5: ; 3:
	inc	ebp ; 18/07/2015
	lodsb   ; mov al, [esi] ; inc esi (al = r4)
		; movb (r2)+,r4 / move a character from u.namep string into r4
	or 	al, al
	jz 	short namei_7
		; beq 3f / if char is nul, then the last char in string
			; / has been moved
	cmp	al, '/'
		; cmp r4,$'/ / is char a </>
	je 	short namei_7
		; beq 3f	
	; 12/10/2015
	dec	cx ; remain byte count in the page
	jnz	short namei_6
	call	trans_addr_nm ; convert virtual address to physical
		; esi = physical address (page start + offset)
		; ecx = byte count in the page
namei_6:
        cmp     edi, u.dirbuf + 16 ; 04/12/2015 (10 -> 16) 
		; cmp r3,$u.dirbuf+10. / have I checked
				     ; / all 8 bytes of file name
	je	short namei_5
		; beq 3b
	scasb	
		; cmpb (r3)+,r4 / compare char in u.namep string to file name 
			      ; / char read from directory
	je 	short namei_5
		; beq 3b / branch if chars match

        jmp    namei_3 ; 2b
		; br 2b / file names do not match go to next directory entry
namei_7: ; 3:
	cmp	edi, u.dirbuf + 16 ; 04/12/2015 (10 -> 16) 
		; cmp r3,$u.dirbuf+10. / if equal all 8 bytes were matched
	je	short namei_8
		; beq 3f
	mov 	ah, [edi]
	;inc 	edi 
	and 	ah, ah
		; tstb (r3)+ /
        jnz     namei_3
		; bne 2b
namei_8: ; 3
	mov	[u.namep], ebp ; 18/07/2015
		; mov r2,u.namep / u.namep points to char 
			       ; / following a / or nul
	;mov	bx, [u.dirbuf]
		; mov u.dirbuf,r1 / move i-node number in directory 
				; / entry to r1
	and 	al, al
		; tst r4 / if r4 = 0 the end of file name reached,
		      ;  / if r4 = </> then go to next directory
	; mov	ax, bx
	mov 	ax, [u.dirbuf] ; 17/06/2015
        jnz     namei_2 
		; bne 1b
	; AX = i-number of the file
;;nig:
	retn
		; tst (r0)+ / gives non-error return
;;nib:
;;	xor	ax, ax ; Retro UNIX 8086 v1 modification !
		       ; ax = 0 -> file not found 
;;	stc	; 27/05/2013
;;	retn
		; rts r0

trans_addr_nmbp:
	; 18/10/2015
	; 12/10/2015
	mov 	ebp, [u.namep]
trans_addr_nm: 
	; Convert virtual (pathname) address to physical address
	; (Retro UNIX 386 v1 feature only !)
	; 18/10/2015
	; 12/10/2015 (u.pnbase & u.pncount has been removed from code)
	; 02/07/2015
	; 17/06/2015
	; 16/06/2015
	;
	; INPUTS: 
	;	ebp = pathname address (virtual) ; [u.namep]
	;	[u.pgdir] = user's page directory
	; OUTPUT:
	;       esi = physical address of the pathname
	;	ecx = remain byte count in the page
	;
	; (Modified registers: EAX, EBX, ECX, EDX, ESI)
	;
        cmp     dword [u.ppgdir], 0  ; /etc/init ? (sysexec)
	jna	short trans_addr_nmk ; the caller is os kernel;
				     ; it is already physical address
   	push	eax	
	mov	ebx, ebp ; [u.namep] ; pathname address (virtual)
       	call	get_physical_addr ; get physical address
	jc	short tr_addr_nm_err
	; 18/10/2015
	; eax = physical address 
	; cx = remain byte count in page (1-4096) 
		; 12/10/2015 (cx = [u.pncount])
	mov	esi, eax ; 12/10/2015 (esi=[u.pnbase])
	pop	eax 
	retn

tr_addr_nm_err:
	mov	[u.error], eax
	;pop 	eax
	jmp	error

trans_addr_nmk:
	; 12/10/2015
	; 02/07/2015
	mov	esi, [u.namep]  ; [u.pnbase]
	mov	cx, PAGE_SIZE ; 4096 ; [u.pncount]
	retn

syschdir:
	; / makes the directory specified in the argument
	; / the current directory
	;
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 19/06/2013 (Retro UNIX 8086 v1)
	;
	; 'syschdir' makes the directory specified in its argument
	; the current working directory.
	;
	; Calling sequence:
	;	syschdir; name
	; Arguments:
	;	name - address of the path name of a directory
	;	       terminated by nul byte.	
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification:
	;	 The user/application program puts address of 
	;	 the path name in BX register as 'syschdir' 
	; 	 system call argument.

	mov	[u.namep], ebx
		;jsr r0,arg; u.namep / u.namep points to path name
	call	namei
		; jsr r0,namei / find its i-number
	;jc	error
		; br error3
	jnc	short syschdir0
	; 'directory not found !' error
	mov	dword [u.error], ERR_DIR_NOT_FOUND ; 12
	jmp	error
syschdir0:
	call	access
		; jsr r0,access; 2 / get i-node into core
	test	word [i.flgs], 4000h
		; bit $40000,i.flgs / is it a directory?
	;jz	error 
		; beq error3 / no error
	jnz	short syschdir1
	mov	dword [u.error], ERR_NOT_DIR ; 'not a valid directory !'
	jmp	error
syschdir1:
	mov	[u.cdir], ax
		; mov r1,u.cdir / move i-number to users 
			      ; / current directory
	mov	ax, [cdev]
	mov	[u.cdrv], ax
		; mov cdev,u.cdev / move its device to users 
			        ; / current device
	jmp	sysret
		; br sysret3
	
syschmod: ; < change mode of file >
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 20/06/2013 - 07/07/2013 (Retro UNIX 8086 v1)
	;
	; 'syschmod' changes mode of the file whose name is given as
	; null terminated string pointed to by 'name' has it's mode 
	; changed to 'mode'.
	;
	; Calling sequence:
	;	syschmod; name; mode
	; Arguments:
	;	name - address of the file name
	;	       terminated by null byte.
	;	mode - (new) mode/flags < attributes >
	;	
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'syschmod' system call has two arguments; so,
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, mode is in CX register
	;
	; Mode bits (Flags):
	;	bit 0 - write permission for non-owner (1)
	;	bit 1 - read permission for non-owner (2)
	;	bit 2 - write permission for owner (4)
	;	bit 3 - read permission for owner (8)
	;	bit 4 - executable flag (16) 	
	;	bit 5 - set user ID on execution flag (32) 
	;	bit 6,7,8,9,10,11 are not used (undefined)
	;	bit 12 - large file flag (4096)
	;	bit 13 - file has modified flag (always on) (8192)
	;	bit 14 - directory flag (16384)
	;	bit 15 - 'i-node is allocated' flag (32768)

	; / name; mode
	call	isown
		;jsr r0,isown / get the i-node and check user status
	test	word [i.flgs], 4000h
		; bit	$40000,i.flgs / directory?
	jz	short syschmod1
		; beq 2f / no
	; AL = (new) mode
	and	al, 0CFh ; 11001111b (clears bit 4 & 5)
		; bic $60,r2 / su & ex / yes, clear set user id and 
			   ; / executable modes
syschmod1: ; 2:
	mov	[i.flgs], al	
		; movb r2,i.flgs / move remaining mode to i.flgs
	jmp	short isown1
		; br 1f

isown:
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 04/05/2013 - 07/07/2013 (Retro UNIX 8086 v1)
	;
	; 'isown' is given a file name (the 1st argument).
	;  It find the i-number of that file via 'namei' 
	;  then gets the i-node into core via 'iget'.
	;  It then tests to see if the user is super user. 
	;  If not, it cheks to see if the user is owner of 
	;  the file. If he is not an error occurs.
	;  If user is the owner 'setimod' is called to indicate
	;  the inode has been modificed and the 2nd argument of
	;  the call is put in r2.
	;
	; INPUTS ->
	;    arguments of syschmod and syschown calls
	; OUTPUTS ->
	;    u.uid - id of user
	;    imod - set to a 1
	;    r2 - contains second argument of the system call				 	
	;
	;   ((AX=R2) output as 2nd argument)
	;
        ; ((Modified registers: eAX, eDX, eBX, eCX, eSI, eDI, eBP))  
	;
		; jsr r0,arg2 / u.namep points to file name
	;; ! 2nd argument on top of stack !
	;; 22/06/2015 - 32 bit modifications
	;; 07/07/2013
	mov	[u.namep], ebx ;; 1st argument
	push 	ecx ;; 2nd argument
	;;
	call	namei
		; jsr r0,namei / get its i-number
       ; Retro UNIX 8086 v1 modification !
       ; ax = 0 -> file not found 
	;and	ax, ax
	;jz	error
	;jc	error ; 27/05/2013
		; br error3
	jnc	short isown0
	; 'file not found !' error
	mov	dword [u.error], ERR_FILE_NOT_FOUND ; 12
	jmp	error
isown0:
	call	iget
		; jsr r0,iget / get i-node into core
	mov	al, [u.uid] ; 02/08/2013
	or	al, al
		; tstb u.uid / super user?
	jz	short isown1
		; beq 1f / yes, branch
	cmp	al, [i.uid]
		; cmpb i.uid,u.uid / no, is this the owner of
				 ; / the file
	;jne	error
		; beq 1f / yes
		; jmp error3 / no, error
	je	short isown1

	mov	dword [u.error], ERR_NOT_OWNER  ; 11
			;  'permission denied !' error
	jmp	error
isown1: ; 1:
	call	setimod
		; jsr r0,setimod / indicates 
		;	       ; / i-node has been modified
	pop	eax ; 2nd argument
		; mov (sp)+,r2 / mode is put in r2 
		       ; / (u.off put on stack with 2nd arg)
	retn
		; rts r0

;;arg:  ; < get system call arguments >
	; 'arg' extracts an argument for a routine whose call is 
	; of form:
	;	sys 'routine' ; arg1
	;		or
	;	sys 'routine' ; arg1 ; arg2
	;		or
	;	sys 'routine' ; arg1;...;arg10 (sys exec) 
	;	
	; INPUTS ->
	;    u.sp+18 - contains a pointer to one of arg1..argn
	;	This pointers's value is actually the value of
	;	update pc at the the trap to sysent (unkni) is
	;	made to process the sys instruction
	;    r0 - contains the return address for the routine
	;	that called arg. The data in the word pointer 
	;	to by the return address is used as address
	;	in which the extracted argument is stored   		
	;    	
	; OUTPUTS ->
	;    'address' - contains the extracted argument 
	;    u.sp+18 - is incremented by 2 
	;    r1 - contains the extracted argument
	;    r0 - points to the next instruction to be
	;	 executed in the calling routine.
	;
  
	; mov u.sp,r1
	; mov *18.(r1),*(r0)+ / put argument of system call
			; / into argument of arg2
	; add $2,18.(r1) / point pc on stack 
			      ; / to next system argument
	; rts r0

;;arg2: ; < get system calls arguments - with file name pointer>
	; 'arg2' takes first argument in system call
	;  (pointer to name of the file) and puts it in location
	;  u.namep; takes second argument and puts it in u.off
	;  and on top of the stack
	;	
	; INPUTS ->
	;    u.sp, r0
	;    	
	; OUTPUTS ->
	;    u.namep
	;    u.off 
	;    u.off pushed on stack
	;    r1
	;

	; jsr	r0,arg; u.namep / u.namep contains value of
				; / first arg in sys call
	; jsr r0,arg; u.off / u.off contains value of 
				; / second arg in sys call
	; mov r0,r1 / r0 points to calling routine
	; mov (sp),r0 / put operation code back in r0
	; mov u.off,(sp) / put pointer to second argument 
			; / on stack
	; jmp (r1) / return to calling routine

syschown: ; < change owner of file >
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 20/06/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'syschown' changes the owner of the file whose name is given
	; as null terminated string pointed to by 'name' has it's owner
	; changed to 'owner'
	;
	; Calling sequence:
	;	syschown; name; owner
	; Arguments:
	;	name - address of the file name
	;	       terminated by null byte.
	;	owner - (new) owner (number/ID)
	;	
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'syschown' system call has two arguments; so,
	;	* 1st argument, name is pointed to by BX register
	;	* 2nd argument, owner number is in CX register
	;
	; / name; owner
	call	isown
		; jsr r0,isown / get the i-node and check user status
	cmp 	byte [u.uid], 0 ; 02/08/2013 
		; tstb u.uid / super user
	jz	short syschown1
		; beq 2f / yes, 2f
        test    byte [i.flgs], 20h ; 32
		; bit $40,i.flgs / no, set userid on execution?
	;jnz	error
		; bne 3f / yes error, could create Trojan Horses
	jz	short syschown1
	; 'permission denied !'
	mov	dword [u.error], ERR_FILE_ACCESS  ; 11
	jmp	error
syschown1: ; 2:
	; AL = owner (number/ID)
	mov	[i.uid], al ; 23/06/2015
		;  movb	r2,i.uid / no, put the new owners id 
			       ; / in the i-node
	jmp	sysret
	; 1: 
		; jmp sysret4
	; 3:
		; jmp	error

systime: ; / get time of year
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 20/06/2013 (Retro UNIX 8086 v1)
	;
	; 20/06/2013
	; 'systime' gets the time of the year.
	; The present time is put on the stack.
	;
	; Calling sequence:
	;	systime
	; Arguments: -
	;	
	; Inputs: -
	; Outputs: sp+2, sp+4 - present time
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       'systime' system call will return to the user
	;	with unix time (epoch) in DX:AX register pair
	;
	; 	!! Major modification on original Unix v1 'systime' 
	;	system call for PC compatibility !!		 	

	call 	epoch
	mov 	[u.r0], eax
		; mov s.time,4(sp)
		; mov s.time+2,2(sp) / put the present time 
				   ; / on the stack
		; br sysret4
	jmp	sysret 

sysstime: ; / set time
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 20/06/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'sysstime' sets the time. Only super user can use this call.
	;
	; Calling sequence:
	;	sysstime
	; Arguments: -
	;	
	; Inputs: sp+2, sp+4 - time system is to be set to.
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;	the user calls 'sysstime' with unix (epoch) time
	;	(to be set) is in CX:BX register pair as two arguments.
	; 
	;	Retro UNIX 8086 v1 argument transfer method 2 is used
	;	to get sysstime system call arguments from the user;
	;	* 1st argument, lowword of unix time is in BX register
	;	* 2nd argument, highword of unix time is in CX register		 	
	;
	; 	!! Major modification on original Unix v1 'sysstime' 
	;	system call for PC compatibility !!	

	cmp	byte [u.uid], 0
		; tstb u.uid / is user the super user
	;ja	error
		; bne error4 / no, error
	jna	short systime1
	; 'permission denied !'
	mov	dword [u.error], ERR_NOT_SUPERUSER  ; 11 
	jmp	error
systime1:
	; 23/06/2015 (Retro UNIX 386 v1 - 32 bit version)
	; EBX = unix (epoch) time (from user)
	mov	eax, ebx
	call 	set_date_time
		; mov 4(sp),s.time
		; mov 2(sp),s.time+2 / set the system time
	jmp	sysret
		; br sysret4

sysbreak:
	; 18/10/2015
	; 07/10/2015
	; 23/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 20/06/2013 - 24/03/2014 (Retro UNIX 8086 v1)
	;
	; 'sysbreak' sets the programs break points. 
	; It checks the current break point (u.break) to see if it is
	; between "core" and the stack (sp). If it is, it is made an
	; even address (if it was odd) and the area between u.break
	; and the stack is cleared. The new breakpoint is then put
	; in u.break and control is passed to 'sysret'.
	;
	; Calling sequence:
	;	sysbreak; addr
	; Arguments: -
	;	
	; Inputs: u.break - current breakpoint
	; Outputs: u.break - new breakpoint 
	;	area between old u.break and the stack (sp) is cleared.
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification:
	;	The user/application program puts breakpoint address
	;       in BX register as 'sysbreak' system call argument.
	; 	(argument transfer method 1)
	;
	;  NOTE: Beginning of core is 0 in Retro UNIX 8086 v1 !
	; 	((!'sysbreak' is not needed in Retro UNIX 8086 v1!))
	;  NOTE:
	; 	'sysbreak' clears extended part (beyond of previous
	;	'u.break' address) of user's memory for original unix's
	;	'bss' compatibility with Retro UNIX 8086 v1 (19/11/2013)

		; mov u.break,r1 / move users break point to r1
		; cmp r1,$core / is it the same or lower than core?
		; blos 1f / yes, 1f
	; 23/06/2015
	mov	ebp, [u.break] ; virtual address (offset)
	;and	ebp, ebp
	;jz	short sysbreak_3 
	; Retro UNIX 386 v1 NOTE: u.break points to virtual address !!!
	; (Even break point address is not needed for Retro UNIX 386 v1)
	mov	edx, [u.sp] ; kernel stack at the beginning of sys call
	add	edx, 12 ; EIP -4-> CS -4-> EFLAGS -4-> ESP (user) 
	; 07/10/2015
	mov	[u.break], ebx ; virtual address !!!
	;
	cmp	ebx, [edx] ; compare new break point with 
			   ; with top of user's stack (virtual!)
	jnb	short sysbreak_3
		; cmp r1,sp / is it the same or higher 
			  ; / than the stack?
		; bhis 1f / yes, 1f
	mov	esi, ebx
	sub	esi, ebp ; new break point - old break point
	jna	short sysbreak_3 
	;push	ebx
sysbreak_1:
	mov	ebx, ebp  
	call	get_physical_addr ; get physical address
	jc	tr_addr_nm_err
	; 18/10/2015
	mov	edi, eax 
	sub	eax, eax ; 0
		 ; ECX = remain byte count in page (1-4096)
	cmp	esi, ecx
	jnb	short sysbreak_2
	mov	ecx, esi
sysbreak_2:
	sub	esi, ecx
	add	ebp, ecx
	rep 	stosb
	or	esi, esi
	jnz	short sysbreak_1
	;
		; bit $1,r1 / is it an odd address
		; beq 2f / no, its even
		; clrb (r1)+ / yes, make it even
	; 2: / clear area between the break point and the stack
		; cmp r1,sp / is it higher or same than the stack
		; bhis 1f / yes, quit
		; clr (r1)+ / clear word
		; br 2b / go back
	;pop	ebx
sysbreak_3: ; 1:
	;mov	[u.break], ebx ; virtual address !!!
		; jsr r0,arg; u.break / put the "address" 
			; / in u.break (set new break point)
		; br sysret4 / br sysret
	jmp	sysret


maknod: 
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 02/05/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'maknod' creates an i-node and makes a directory entry
	; for this i-node in the current directory.
	;
	; INPUTS ->
	;    r1 - contains mode
	;    ii - current directory's i-number	
	;    	
	; OUTPUTS ->
	;    u.dirbuf - contains i-number of free i-node 
	;    i.flgs - flags in new i-node 
	;    i.uid - filled with u.uid
	;    i.nlks - 1 is put in the number of links
	;    i.ctim - creation time				
	;    i.ctim+2 - modification time
	;    imod - set via call to setimod
	;	
	; ((AX = R1)) input
	;
	; (Retro UNIX Prototype : 
	;	30/10/2012 - 01/03/2013, UNIXCOPY.ASM)
        ; ((Modified registers: eAX, eDX, eBX, eCX, eSI, eDI, eBP))  

	; / r1 contains the mode
	or 	ah, 80h  ; 10000000b
		; bis	$100000,r1 / allocate flag set
	push	ax
		; mov r1,-(sp) / put mode on stack
	; 31/07/2013
	mov	ax, [ii] ; move current i-number to AX/r1
		; mov ii,r1 / move current i-number to r1
	mov	dl, 1 ; owner flag mask
	call	access	
		; jsr r0,access; 1 / get its i-node into core
	push	ax
		; mov r1,-(sp) / put i-number on stack
	mov	ax, 40
		; mov $40.,r1 / r1 = 40
maknod1: ; 1: / scan for a free i-node (next 4 instructions)
	inc	ax
		; inc r1 / r1 = r1 + 1
	call	imap
		; jsr r0,imap / get byte address and bit position in 
			    ; /	inode map in r2 & m
          ; DX (MQ) has a 1 in the calculated bit position
          ; eBX (R2) has byte address of the byte with allocation bit
	; 22/06/2015 - NOTE for next Retro UNIX version: 
	;	       Inode count must be checked here
	; (Original UNIX v1 did not check inode count here !?) 	
	test	[ebx], dl
		; bitb mq,(r2) / is the i-node active
	jnz	short maknod1
		; bne 1b / yes, try the next one
	or	[ebx], dl
		; bisb mq,(r2) / no, make it active 
			     ; / (put a 1 in the bit map)
	call	iget
		; jsr r0,iget / get i-node into core
	test	word [i.flgs], 8000h 
		; tst i.flgs / is i-node already allocated
	jnz	short maknod1	
		; blt 1b / yes, look for another one
	mov	[u.dirbuf], ax
		; mov r1,u.dirbuf / no, put i-number in u.dirbuf
	pop	ax
		; mov (sp)+,r1 / get current i-number back
	call	iget
		; jsr r0,iget / get i-node in core
	call	mkdir
		; jsr r0,mkdir / make a directory entry 
			     ; / in current directory
	mov	ax, [u.dirbuf]
		; mov u.dirbuf,r1 / r1 = new inode number
	call	iget
		; jsr r0,iget / get it into core
		; jsr r0,copyz; inode; inode+32. / 0 it out
	mov	ecx, 8 
	xor	eax, eax ; 0
	mov	edi, inode 
	rep	stosd
	;
	pop	word [i.flgs]
		; mov (sp)+,i.flgs / fill flags
	mov 	cl, [u.uid] ; 02/08/2013
	mov 	[i.uid], cl
		; movb u.uid,i.uid / user id	
	mov     byte [i.nlks], 1
		; movb $1,i.nlks / 1 link
	;call	epoch ; Retro UNIX 8086 v1 modification !
	;mov	eax, [s.time]
	;mov 	[i.ctim], eax
	 	; mov s.time,i.ctim / time created
	 	; mov s.time+2,i.ctim+2 / time modified
	; Retro UNIX 8086 v1 modification !
	; i.ctime=0, i.ctime+2=0 and
        ; 'setimod' will set ctime of file via 'epoch'
	call setimod
		; jsr r0,setimod / set modified flag
	retn
		; rts r0 / return

sysseek: ; / moves read write pointer in an fsp entry
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 - 05/08/2013 (Retro UNIX 8086 v1)
	;
	; 'sysseek' changes the r/w pointer of (3rd word of in an
	; fsp entry) of an open file whose file descriptor is in u.r0.
	; The file descriptor refers to a file open for reading or
	; writing. The read (or write) pointer is set as follows:
	;	* if 'ptrname' is 0, the pointer is set to offset.
	;	* if 'ptrname' is 1, the pointer is set to its
	;	  current location plus offset.
	;	* if 'ptrname' is 2, the pointer is set to the
	;	  size of file plus offset.
	; The error bit (e-bit) is set for an undefined descriptor.
	;
	; Calling sequence:
	;	sysseek; offset; ptrname
	; Arguments:
	;	offset - number of bytes desired to move 
	;		 the r/w pointer
	;	ptrname - a switch indicated above
	;
	; Inputs: r0 - file descriptor 
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       'sysseek' system call has three arguments; so,
	;	* 1st argument, file descriptor is in BX (BL) register
	;	* 2nd argument, offset is in CX register
	;	* 3rd argument, ptrname/switch is in DX (DL) register	
	;	

	call	seektell
	; AX = u.count
	; BX = *u.fofp
		; jsr r0,seektell / get proper value in u.count
		; add u.base,u.count / add u.base to it
	add	eax, [u.base] ; add offset (u.base) to base
	mov	[ebx], eax
		; mov u.count,*u.fofp / put result into r/w pointer
	jmp	sysret
		; br sysret4

systell: ; / get the r/w pointer
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 - 05/08/2013 (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 modification:
	; ! 'systell' does not work in original UNIX v1,
	; 	    it returns with error !
	; Inputs: r0 - file descriptor 
	; Outputs: r0 - file r/w pointer

	;xor	ecx, ecx ; 0
	mov	edx, 1 ; 05/08/2013
	;call 	seektell
	call 	seektell0 ; 05/08/2013
	;mov	ebx, [u.fofp]
	mov	eax, [ebx]
	mov	[u.r0], eax
	jmp	sysret

; Original unix v1 'systell' system call:
		; jsr r0,seektell
		; br error4

seektell:
	; 03/01/2016
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 - 05/08/2013 (Retro UNIX 8086 v1)
	;
	; 'seektell' puts the arguments from sysseek and systell
	; call in u.base and u.count. It then gets the i-number of
	; the file from the file descriptor in u.r0 and by calling
	; getf. The i-node is brought into core and then u.count
	; is checked to see it is a 0, 1, or 2.
	; If it is 0 - u.count stays the same
	;          1 - u.count = offset (u.fofp)
	;	   2 - u.count = i.size (size of file)
	; 	 		
	; !! Retro UNIX 8086 v1 modification:
	;	Argument 1, file descriptor is in BX;
	;	Argument 2, offset is in CX;
	;	Argument 3, ptrname/switch is in DX register.	
	;
	; mov 	ax, 3 ; Argument transfer method 3 (three arguments)	
	; call 	arg
	;
	; ((Return -> ax = base for offset (position= base+offset))
	;
	mov 	[u.base], ecx ; offset
		; jsr r0,arg; u.base / puts offset in u.base
seektell0:
	mov 	[u.count], edx
		; jsr r0,arg; u.count / put ptr name in u.count
	; mov	ax, bx
		; mov *u.r0,r1 / file descriptor in r1 
			     ; / (index in u.fp list)
	; call	getf
		; jsr r0,getf / u.fofp points to 3rd word in fsp entry
	; BX = file descriptor (file number)
	call	getf1
	or	ax, ax ; i-number of the file
		; mov r1,-(sp) / r1 has i-number of file, 
		             ; / put it on the stack
	;jz	error
		; beq error4 / if i-number is 0, not active so error
	jnz	short seektell1
	mov	dword [u.error], ERR_FILE_NOT_OPEN  ; 'file not open !'
	jmp	error
seektell1:
	;push	eax
	cmp	ah, 80h
	jb	short seektell2
		; bgt .+4 / if its positive jump
	neg	ax
		; neg r1 / if not make it positive
seektell2:
	call	iget
		; jsr r0,iget / get its i-node into core
        mov     ebx, [u.fofp] ; 05/08/2013
	cmp	byte [u.count], 1
		; cmp u.count,$1 / is ptr name =1
	ja	short seektell3
		; blt 2f / no its zero
	je	short seektell_4
		; beq 1f / yes its 1
	xor	eax, eax
	;jmp	short seektell_5
	retn
seektell3:
	; 03/01/2016
	;movzx	eax, word [i.size]
        mov   	ax, [i.size]
                ; mov i.size,u.count /  put number of bytes 
                                   ; / in file in u.count
	;jmp	short seektell_5
		; br 2f
	retn
seektell_4: ; 1: / ptrname =1
	;mov	ebx, [u.fofp]
	mov	eax, [ebx]
		; mov *u.fofp,u.count / put offset in u.count
;seektell_5: ; 2: / ptrname =0
	;mov	[u.count], eax
	;pop	eax 
		; mov (sp)+,r1 / i-number on stack  r1
	retn
		; rts r0

sysintr: ; / set interrupt handling
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 (Retro UNIX 8086 v1)
	;
	; 'sysintr' sets the interrupt handling value. It puts
	; argument of its call in u.intr then branches into 'sysquit'
	; routine. u.tty is checked if to see if a control tty exists.
	; If one does the interrupt character in the tty buffer is
	; cleared and 'sysret'is called. If one does not exits
	; 'sysret' is just called.	
	;
	; Calling sequence:
	;	sysintr; arg
	; Argument:
	;	arg - if 0, interrupts (ASCII DELETE) are ignored.
	;	    - if 1, intterupts cause their normal result
	;		 i.e force an exit.
	;	    - if arg is a location within the program,
	;		control is passed to that location when
	;		an interrupt occurs.	
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       'sysintr' system call sets u.intr to value of BX
	;	then branches into sysquit.
	;
	mov	[u.intr], bx
		; jsr r0,arg; u.intr / put the argument in u.intr
		; br 1f / go into quit routine
	jmp	sysret

sysquit:
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 (Retro UNIX 8086 v1)
	;
	; 'sysquit' turns off the quit signal. it puts the argument of
	; the call in u.quit. u.tty is checked if to see if a control 
	; tty exists. If one does the interrupt character in the tty
	; buffer is cleared and 'sysret'is called. If one does not exits
	; 'sysret' is just called.	
	;
	; Calling sequence:
	;	sysquit; arg
	; Argument:
	;	arg - if 0, this call diables quit signals from the
	;		typewriter (ASCII FS)
	;	    - if 1, quits are re-enabled and cause execution to
	;		cease and a core image to be produced.
	;		 i.e force an exit.
	;	    - if arg is an addres in the program,
	;		a quit causes control to sent to that
	;		location.	
	; Inputs: -
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       'sysquit' system call sets u.quit to value of BX
	;	then branches into 'sysret'.
	;
	mov	[u.quit], bx
	jmp	sysret
		; jsr r0,arg; u.quit / put argument in u.quit
	;1:
		; mov u.ttyp,r1 / move pointer to control tty buffer
			      ; / to r1
		; beq sysret4 / return to user
		; clrb 6(r1) / clear the interrupt character 
			   ; / in the tty buffer
		; br sysret4 / return to user

syssetuid: ; / set process id
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 - 02/08/2013 (Retro UNIX 8086 v1)
	;
	; 'syssetuid' sets the user id (u.uid) of the current process
	; to the process id in (u.r0). Both the effective user and 
	; u.uid and the real user u.ruid are set to this. 
	; Only the super user can make this call.	
	;
	; Calling sequence:
	;	syssetuid
	; Arguments: -
	;
	; Inputs: (u.r0) - contains the process id.
	; Outputs: -
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       BL contains the (new) user ID of the current process

		; movb *u.r0,r1 / move process id (number) to r1
	cmp	bl, [u.ruid] 
		; cmpb r1,u.ruid / is it equal to the real user 
			       ; / id number
	je	short setuid1
		; beq 1f / yes
	cmp	byte [u.uid], 0 ; 02/08/2013
		; tstb u.uid / no, is current user the super user?
	;ja	error
		; bne error4 / no, error
	jna	short setuid0
	mov	dword [u.error], ERR_NOT_SUPERUSER  ; 11
				;  'permission denied !' error
	jmp	error
setuid0:
	mov	[u.ruid], bl
setuid1: ; 1:
	mov	[u.uid], bl ; 02/08/2013
		; movb r1,u.uid / put process id in u.uid
		; movb r1,u.ruid / put process id in u.ruid
	jmp	sysret
		; br sysret4 / system return

sysgetuid: ; < get user id >
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 07/07/2013 (Retro UNIX 8086 v1)
	;
	; 'sysgetuid' returns the real user ID of the current process.
	; The real user ID identifies the person who is logged in,
	; in contradistinction to the effective user ID, which
	; determines his access permission at each moment. It is thus
	; useful to programs which operate using the 'set user ID'
	; mode, to find out who invoked them.	
	;
	; Calling sequence:
	;	syssetuid
	; Arguments: -
	;
	; Inputs: -
	; Outputs: (u.r0) - contains the real user's id.
	; ...............................................................
	;	
	; Retro UNIX 8086 v1 modification: 
	;       AL contains the real user ID at return.
	;
	movzx 	eax, byte [u.ruid]
	mov	[u.r0], eax
		; movb	u.ruid,*u.r0 / move the real user id to (u.r0)
	jmp	sysret
		; br sysret4 / systerm return, sysret

anyi: 
	; 22/06/2015 (Retro UNIX 386 v1 - Beginning)
	; 25/04/2013 (Retro UNIX 8086 v1)
	;
	; 'anyi' is called if a file deleted while open.
	; "anyi" checks to see if someone else has opened this file.
	;
	; INPUTS ->
	;    r1 - contains an i-number
	;    fsp - start of table containing open files
	;
	; OUTPUTS ->
	;    "deleted" flag set in fsp entry of another occurrence of
	;	   this file and r2 points 1st word of this fsp entry.
	;    if file not found - bit in i-node map is cleared
	;    			 (i-node is freed)
	;               all blocks related to i-node are freed
	;	        all flags in i-node are cleared
	; ((AX = R1)) input
	;
	;    (Retro UNIX Prototype : 02/12/2012, UNIXCOPY.ASM)
        ;    ((Modified registers: eDX, eCX, eBX, eSI, eDI, eBP))  
	;
		; / r1 contains an i-number
	mov	ebx, fsp
		; mov $fsp,r2 / move start of fsp table to r2
anyi_1: ; 1:
	cmp	ax, [ebx]
		; cmp r1,(r2) / do i-numbers match?
	je	short anyi_3
		; beq 1f / yes, 1f
	neg	ax
		; neg r1 / no complement r1
	cmp	ax, [ebx]
		; cmp r1,(r2) / do they match now?
	je	short anyi_3
		; beq 1f / yes, transfer
		; / i-numbers do not match
	add	ebx, 10 ; fsp table size is 10 bytes
			; in Retro UNIX 386 v1 (22/06/2015)
		; add $8,r2 / no, bump to next entry in fsp table
	cmp	ebx, fsp + (nfiles*10) ; 22/06/2015 
		; cmp r2,$fsp+[nfiles*8] 
				; / are we at last entry in the table
	jb	short anyi_1
		; blt 1b / no, check next entries i-number
	;cmp	ax, 32768
	cmp	ah, 80h ; negative number check
		; tst r1 / yes, no match
		; bge .+4
	jb	short anyi_2
	neg	ax
		; neg r1 / make i-number positive
anyi_2:	
	call	imap
		; jsr r0,imap / get address of allocation bit 
			    ; / in the i-map in r2
	;; DL/DX (MQ) has a 1 in the calculated bit position
        ;; eBX (R2) has address of the byte with allocation bit
 	; not	dx
	not 	dl ;; 0 at calculated bit position, other bits are 1
        ;and	[ebx], dx
	and 	[ebx], dl 
		; bicb mq,(r2) / clear bit for i-node in the imap
	call	itrunc
		; jsr r0,itrunc / free all blocks related to i-node
 	mov 	word [i.flgs], 0
		; clr i.flgs / clear all flags in the i-node
	retn
		;rts	r0 / return
anyi_3: ; 1: / i-numbers match
	inc 	byte [ebx+9] ; 22/06/2015
		;incb 7(r2) / increment upper byte of the 4th word
		   ; / in that fsp entry (deleted flag of fsp entry)
	retn
		; rts r0

; Retro UNIX 386 v1 Kernel (v0.2) - u7.s
; Last Modification: 14/11/2015

sysmount: ; / mount file system; args special; name
	; 14/11/2015
	; 24/10/2015
	; 13/10/2015
	; 10/07/2015
	; 16/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 09/07/2013 - 04/11/2013 (Retro UNIX 8086 v1)
	;
	; 'sysmount' anounces to the system that a removable 
	; file system has been mounted on a special file.
	; The device number of the special file is obtained via
	; a call to 'getspl'. It is put in the I/O queue entry for
	; dismountable file system (sb1) and the I/O queue entry is
	; set up to read (bit 10 is set). 'ppoke' is then called to
	; to read file system into core, i.e. the first block on the
	; mountable file system is read in. This block is super block
	; for the file system. This call is super user restricted.	
	;
	; Calling sequence:
	;	sysmount; special; name
	; Arguments:
	;	special - pointer to name of special file (device)
	;	name -  pointer to name of the root directory of the
	;		newly mounted file system. 'name' should 
	;		always be a directory.
	; Inputs: - 
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysmount' system call has two arguments; so,
	;	* 1st argument, special is pointed to by BX register
	;	* 2nd argument, name is in CX register
	;
	;	NOTE: Device numbers, names and related procedures are 
	;	       already modified for IBM PC compatibility and 
	;	       Retro UNIX 8086 v1 device configuration.	
	
	;call	arg2
		; jsr r0,arg2 / get arguments special and name
	mov	[u.namep], ebx
	push	ecx ; directory name
	cmp	word [mnti], 0
		; tst mnti / is the i-number of the cross device file
			 ; / zero?
	;ja	error
        	; bne errora / no, error
	ja	sysmnt_err0
	;
	call	getspl
		; jsr r0,getspl / get special files device number in r1
	; 13/10/2015
	movzx	ebx, ax ; ; Retro UNIX 8086 v1 device number (0 to 5)
        test    byte [ebx+drv.status], 80h ; 24/10/2015 
	jnz	short sysmnt_1
sysmnt_err1:
        mov     dword [u.error], ERR_DRV_NOT_RDY ; drive not ready !
	jmp	error
sysmnt_1:
	pop	dword [u.namep]
        	; mov (sp)+,u.namep / put the name of file to be placed
				  ; / on the device
	; 14/11/2015
	push	ebx ; 13/10/2015
		; mov r1,-(sp) / save the device number
        ;
	call	namei
	;or	ax, ax ; Retro UNIX 8086 v1 modification !
		       ; ax = 0 -> file not found 	
	;jz	error
	;jc	error
		; jsr r0,namei / get the i-number of the file
               	; br errora
	jnc	short sysmnt_2
sysmnt_err2:
        mov     dword [u.error], ERR_FILE_NOT_FOUND ; drive not ready !
	jmp	error
sysmnt_2:	
	mov	[mnti], ax
        	; mov r1,mnti / put it in mnti
;	mov	ebx, sb1 ; super block buffer (of mounted disk)
sysmnt_3: ;1:
        ;cmp	byte [ebx+1], 0
		; tstb sb1+1 / is 15th bit of I/O queue entry for
			   ; / dismountable device set?
        ;jna	short sysmnt_4		
		; bne 1b / (inhibit bit) yes, skip writing
	;call	idle 	; (wait for hardware interrupt)
	;jmp	short sysmnt_3
sysmnt_4:   
	pop	eax ; Retro UNIX 8086 v1 device number/ID (0 to 5)     
	mov	[mdev], al
		; mov  (sp),mntd / no, put the device number in mntd
	mov	[ebx], al
        	; movb (sp),sb1 / put the device number in the lower byte
			      ; / of the I/O queue entry
	;mov	byte [cdev], 1 ; mounted device/drive
        	; mov (sp)+,cdev / put device number in cdev
        or	word [ebx], 400h ; Bit 10, 'read' flag/bit
		; bis $2000,sb1 / set the read bit
	; Retro UNIX 386 v1 modification : 
	;	32 bit block number at buffer header offset 4
	mov	dword [ebx+4], 1 ; physical block number = 1
	call 	diskio
	jnc	short sysmnt_5
	xor 	eax, eax
	mov	[mnti], ax ; 0
	mov	[mdev], al ; 0
	;mov	[cdev], al ; 0
sysmnt_invd:
	; 14/11/2015
	dec 	al
	mov	[ebx], eax ; 000000FFh
	inc	al
	dec	eax
	mov	[ebx+4], eax ; 0FFFFFFFFh
	jmp	error
sysmnt_5:
	; 14/11/2015 (Retro UNIX 386 v1 modification)
	; (Following check is needed to prevent mounting an
	; in valid valid file system (in valid super block).
	; 
	movzx	eax, byte [ebx] ; device number
	shl	al, 2 ; 4*index
	mov	ecx, [eax+drv.size] ; volume (fs) size
	shl 	ecx, 3
	movzx	edx, word [sb1+4] ; the 1st data word
	cmp	ecx, edx ; compare free map bits and volume size
			 ; (in sectors), if they are not equal
			 ; the disk to be mounted is an...	
	jne	short sysmnt_invd ; invalid disk !
			 ; (which has not got a valid super block)
	;
	mov	byte [ebx+1], 0
	       	; jsr r0,ppoke / read in entire file system
;sysmnt_6: ;1:
	;;cmp	byte [sb1+1], 0
		; tstb   sb1+1 / done reading?
   	;;jna	sysret
	;;call	idle ; (wait for hardware interrupt)
	;;jmp	short sysmnt_6
		;bne 1b / no, wait
        	;br sysreta / yes
	jmp	sysret

sysumount: ; / special dismount file system
	; 16/05/2015 (Retro UNIX 386 v1 - Beginning)
	; 09/07/2013 - 04/11/2013 (Retro UNIX 8086 v1)
	;
	; 04/11/2013
	; 09/07/2013
	; 'sysumount' anounces to the system that the special file, 
	; indicated as an argument is no longer contain a removable
	; file system. 'getspl' gets the device number of the special
	; file. If no file system was mounted on that device an error
	; occurs. 'mntd' and 'mnti' are cleared and control is passed
	; to 'sysret'.
	;
	; Calling sequence:
	;	sysmount; special
	; Arguments:
	;	special - special file to dismount (device)
	;
	; Inputs: - 
	; Outputs: -
	; ...............................................................
	;				
	; Retro UNIX 8086 v1 modification: 
	;       'sysumount' system call has one argument; so,
	;	* Single argument, special is pointed to by BX register
	;
	
	;mov 	ax, 1 ; one/single argument, put argument in BX	
	;call	arg
		; jsr r0,arg; u.namep / point u.namep to special
        mov	[u.namep], ebx
	call	getspl
		; jsr r0,getspl / get the device number in r1
	cmp	al, [mdev]
		; cmp r1,mntd / is it equal to the last device mounted?
	jne	short sysmnt_err0 ; 'permission denied !' error
	;jne	error
        	; bne errora / no error
	xor	al, al ; ah = 0
sysumnt_0: ;1:
     	cmp 	[sb1+1], al ; 0
		; tstb sb1+1 / yes, is the device still doing I/O 
			   ; / (inhibit bit set)?
	jna	short sysumnt_1		
		; bne 1b / yes, wait
	call	idle ; (wait for hardware interrupt)
	jmp	short sysumnt_0
sysumnt_1:        
	mov	[mdev], al
	     	; clr mntd / no, clear these
   	mov	[mnti], ax
        	; clr mnti
        jmp	sysret
		; br sysreta / return

getspl: ; / get device number from a special file name
	call	namei
	;or	ax, ax ; Retro UNIX 8086 v1 modification !
		       ; ax = 0 -> file not found 	
        jc      sysmnt_err2 ; 'file not found !' error
	;jz	error
	;jc	error
		; jsr r0,namei / get the i-number of the special file
                ; br errora / no such file
        sub	ax, 3 ; Retro UNIX 8086 v1 modification !
		      ;	i-number-3, 0 = fd0, 5 = hd3 
		; sub $4,r1 / i-number-4 rk=1,tap=2+n
        jc	short sysmnt_err0 ; 'permission denied !' error
	;jc	error
		; ble errora / less than 0?  yes, error
        cmp	ax, 5 ;
		; cmp  r1,$9. / greater than 9  tap 7
	ja	short sysmnt_err0 ; 'permission denied !' error
	;ja	error
        	; bgt errora / yes, error
        ; AX = Retro UNIX 8086 v1 Device Number (0 to 5)
iopen_retn:
	retn
		; rts    r0 / return with device number in r1
sysmnt_err0:
	mov	dword [u.error], ERR_FILE_ACCESS ; permission denied !
	jmp	error

; Retro UNIX 386 v1 Kernel (v0.2) - SYS9.INC
; Last Modification: 09/12/2015

syssleep:
	; 29/06/2015 - (Retro UNIX 386 v1)
	; 11/06/2014 - (Retro UNIX 8086 v1)
	;
	; Retro UNIX 8086 v1 feature only
	; (INPUT -> none)
	;
	movzx	ebx, byte [u.uno] ; process number
	mov	ah, [ebx+p.ttyc-1] ; current/console tty
	call	sleep
	jmp	sysret

vp_clr:
	; Reset/Clear Video Page
	;
	; 30/06/2015 - (Retro UNIX 386 v1)
	; 21/05/2013 - 30/10/2013(Retro UNIX 8086 v1) (U0.ASM)
	;
	; Retro UNIX 8086 v1 feature only !
	;
	; INPUTS -> 
	;   BL = video page number	 
	;
	; OUTPUT ->
	;   none
	; ((Modified registers: eAX, BH, eCX, eDX, eSI, eDI))
	;
	; 04/12/2013
	sub	al, al
	; al = 0 (clear video page)
	; bl = video page
	mov	ah, 07h
	; ah = 7 (attribute/color)
	xor 	cx, cx ; 0, left upper column (cl) & row (cl)
	mov	dx, 184Fh ; right lower column & row (dl=24, dh=79)
	call	_scroll_up
	; bl = video page
	xor	dx, dx ; 0 (cursor position) 
	jmp 	_set_cpos

sysmsg:
	; 11/11/2015
	; 01/07/2015 - (Retro UNIX 386 v1 feature only!)
	; Print user-application message on user's console tty
	;
	; Input -> EBX = Message address
	;	   ECX = Message length (max. 255)
	;	   DL = Color (IBM PC Rombios color attributes)
	;
	cmp	ecx, MAX_MSG_LEN ; 255
	ja	sysret ; nothing to do with big message size
	or	cl, cl
	jz	sysret
	and	dl, dl
	jnz	short sysmsg0
	mov	dl, 07h ; default color
		; (black background, light gray character) 
sysmsg0:
	mov	[u.base], ebx
	mov	[ccolor], dl ; color attributes
	mov	ebp, esp
	xor	ebx, ebx ; 0
	mov	[u.nread], ebx ; 0
	;
	cmp	[u.kcall], bl ; 0
	ja	short sysmsgk ; Temporary (01/07/2015)
	;
	mov	[u.count], ecx
	inc	ecx ; + 00h ; ASCIZZ
	sub	esp, ecx
	mov	edi, esp
	mov	esi, esp
	mov	[u.pcount], bx ; reset page (phy. addr.) counter
	; 11/11/2015
	mov 	ah, [u.ttyp] ; recent open tty
	; 0 = none
	dec	ah
	jns	short sysmsg1 
	mov	bl, [u.uno] ; process number	
	mov	ah, [ebx+p.ttyc-1] ; user's (process's) console tty
sysmsg1:
	mov	[u.ttyn], ah
sysmsg2:
	call	cpass
	jz	short sysmsg5
	stosb
	and	al, al
	jnz	short sysmsg2
sysmsg3:
	cmp	ah, 7 ; tty number
	ja	short sysmsg6 ; serial port
	call	print_cmsg
sysmsg4:
	mov	esp, ebp	
	jmp	sysret
sysmsg5:
	mov	byte [edi], 0
	jmp	short sysmsg3
sysmsg6:
	mov	al, [esi]
	call	sndc
	jc	short sysmsg4
	cmp	byte [esi], 0  ; 0 is stop character
	jna	short sysmsg4
	inc 	esi
	mov	ah, [u.ttyn]
	jmp	short sysmsg6

sysmsgk: ; Temporary (01/07/2015)
	; The message has been sent by Kernel (ASCIIZ string)
	; (ECX -character count- will not be considered)
	mov	esi, [u.base]
	mov	ah, [ptty] ; present/current screen (video page)
	mov	[u.ttyn], ah
	mov	byte [u.kcall], 0
	jmp	short sysmsg3
	

print_cmsg: 
	; 01/07/2015 (retro UNIX 386 v1 feature only !)
	;
	; print message (on user's console tty) 
	;	with requested color
	;
	; INPUTS:
	;	esi = message address
	;	[u.ttyn] = tty number (0 to 7)
	;	[ccolor] = color attributes (IBM PC BIOS colors)
	;
	lodsb
pcmsg1:
	push 	esi
        movzx   ebx, byte [u.ttyn]
	mov	ah, [ccolor]
	call 	WRITE_TTY
	pop	esi
	lodsb
	and 	al, al  ; 0
	jnz 	short pcmsg1
	retn

sysgeterr:
	; 09/12/2015
	; 21/09/2015 - (Retro UNIX 386 v1 feature only!)
	; Get last error number or page fault count
	; (for debugging)
	;
	; Input -> EBX = return type
	;	   0 = last error code (which is in 'u.error')	
	;	   FFFFFFFFh = page fault count for running process
	;	   FFFFFFFEh = total page fault count
	;	   1 .. FFFFFFFDh = undefined 
	;
	; Output -> EAX = last error number or page fault count
	;	   (depending on EBX input)
	; 	
	and 	ebx, ebx
	jnz	short glerr_2
glerr_0:
	mov	eax, [u.error]
glerr_1:
	mov	[u.r0], eax
 	retn
glerr_2:
	inc	ebx ; FFFFFFFFh -> 0, FFFFFFFEh -> FFFFFFFFh
	jz	short glerr_2 ; page fault count for process
	inc	ebx ; FFFFFFFFh -> 0	
	jnz	short glerr_0
	mov	eax, [PF_Count] ; total page fault count
        jmp     short glerr_1
glerr_3:
	mov 	eax, [u.pfcount]
	jmp	short glerr_1

; temporary - 24/01/2016

iget:
	retn
poke:
	retn
tswap:
	retn
isintr:
	retn
writei:
	retn
readi:
	retn
putlu:
	retn
swap:
	retn
wswap:
	retn
rswap:
	retn
iopen:
	retn
iclose:
	retn
itrunc:
	retn
clock:
	retn
setimod:
	retn
ottyp:
	retn
cttyp:
	retn
sndc:
	retn
access:
	retn
cpass:
	retn
passc:
	retn
epoch:
	retn
set_date_time:
	retn
imap:
	retn
diskio:
	retn
idle:
	retn
sleep:
	retn



