; ****************************************************************************
; TRDOS386.ASM (TRDOS 386 Kernel - v2.0.3) - SYS INIT : trdosk1.s
; ----------------------------------------------------------------------------
; Last Update: 06/12/2020
; ----------------------------------------------------------------------------
; Beginning: 04/01/2016
; ----------------------------------------------------------------------------
; Assembler: NASM version 2.15 (trdos386.s)
; ----------------------------------------------------------------------------
; Derived from TRDOS Operating System v1.0 (8086) source code by Erdogan Tan
; TRDOS2.ASM (09/11/2011)
; ****************************************************************************
; TRDOS2.ASM (c) 2004-2011 Erdogan TAN [ 17/01/2004 ] Last Update: 09/11/2011
;

sys_init:
	; 20/01/2018  (v2.0.1)
	; 23/01/2017  (v2.0.0)
	; 07/05/2016
	; 02/05/2016
	; 24/04/2016
	; 14/04/2016
	; 13/04/2016
	; 30/03/2016
	; 24/01/2016
	; 06/01/2016
	; 04/01/2016

	; 23/01/2017 - reset timer frequency (to 18.2Hz)
	mov	al, 00110110b ; 36h
 	out	43h, al
	xor	eax, eax  ; sub	al, al ; 0
	out	40h, al ; LB
	out	40h, al ; HB
 	; 
	; 30/03/2016
	; Clear Logical DOS Disk Description Tables Area
	;xor	eax, eax
	mov	edi, Logical_DOSDisks
	mov	ecx, 6656/4 ; 26*256 = 6656 bytes
	rep	stosd ; 1664 times 4 bytes

	mov	eax, '?:/'
	mov	[Current_Dir_Drv], eax

	; Logical DRV INIT (only for hard disks)
	call 	ldrv_init  ; trdosk2.s
	
	; When floppy_drv_init call is disabled
	; media changed sign is needed
	; for proper drive initialization
        
	mov 	esi, Logical_DOSDisks
	mov 	al, 1 ; Initialization sign (invalid_fd_parameter)
	add 	esi, LD_MediaChanged ; Media Change Status = 1 (init needed)
	mov 	[esi], al ; A:
	add 	esi, 100h 
	mov 	[esi], al ; B: 
           
_current_drive_bootdisk:
	mov 	dl, [boot_drv] ; physical drive number
	cmp 	dl, 0FFh
	je 	short _last_dos_diskno_check
_boot_drive_check:
	cmp 	dl, 80h
	jb 	short _current_drive_a
	sub 	dl, 7Eh ; C = 2 , D = 3
	jmp 	short _current_drive_a 

_last_dos_diskno_check:
	mov 	dl, [Last_DOS_DiskNo]
	cmp 	dl, 2
	ja 	short _current_drive_c
	je 	short _current_drive_a
	xor 	dl, dl ; A:
	jmp 	short _current_drive_a

_current_drive_c:
	mov 	dl, 2 ; C:

_current_drive_a:
	mov	[drv], dl
        mov     esi, msg_CRLF_temp
	call 	print_msg

	mov	dl, [drv]
_default_drive_c:
	call 	change_current_drive
	jnc 	short _start_mainprog

_drv_not_ready_error: 
	mov 	esi, msgl_drv_not_ready
	call 	print_msg
        ;jmp	_end_of_mainprog

	; 20/01/2018
	mov	dl, 2
	cmp	[drv], dl
	jnb	short _end_of_mainprog
	mov	[drv], dl
	jmp	short _default_drive_c

_start_mainprog:
	; 07/01/2017
	; 07/05/2016
	; 02/05/2016
	; 24/04/2016
	; Retro UNIX 386 v1, 'sys_init' (u0.s)
	; 23/06/2015

	; 02/05/2016
	; 24/04/2016
	mov	ax, 1
	mov	[u.uno], al
	mov	[mpid], ax
	mov	[p.pid], ax
	mov	[p.stat], al
	mov	byte [u.quant], time_count  ; 07/01/2017
	;
	mov	eax, [k_page_dir]
	mov	[u.pgdir], eax ; reset
	;
	call	allocate_page
	jc	panic
	mov	[u.upage], eax ; user structure page	
	mov	[p.upage], eax
	call	clear_page
	;
	; 24/08/2015
	dec 	byte [sysflg] ; FFh = ready for system call
			      ; 0 = executing a system call
	; 13/04/2016
	; Clear Environment Variables Page/Area
	mov	edi, Env_Page ; 93000h
	mov	ecx, Env_Page_Size / 4 	; 512/4  (4096/4)				 	  		 	  
	xor	eax, eax
	rep	stosd

	; 14/04/2016
 	call	mainprog_startup_configuration

        call    dos_prompt
              
_end_of_mainprog:
        mov     esi, msg_CRLF_temp
	call 	print_msg
	mov 	esi, mainprog_Version
	call 	print_msg
	; 24/01/2016
	sub	ah, ah
	call	int16h ; call getch
	jmp	cpu_reset

infinitiveloop: jmp short infinitiveloop

print_msg:
	; 13/05/2016
	; 04/01/2016
	; 01/07/2015
	; 13/03/2015 (Retro UNIX 386 v1)
	; 07/03/2014 (Retro UNIX 8086 v1)
	; (Modified registers: EAX, EBX, ECX, EDX, ESI, EDI)
	;
	mov	bh, [ACTIVE_PAGE] ; 04/01/2016 (ptty)
	;mov	bl, 07h ; Black background, light gray forecolor

	lodsb
pmsg1:
	push 	esi
	;mov	bh, [ACTIVE_PAGE] ; 04/01/2016 (ptty)
	mov	bl, 07h ; Black background, light gray forecolor
	call 	_write_tty
	pop	esi
	lodsb
	and 	al, al
	jnz 	short pmsg1
	retn

clear_screen:
	; 06/12/2020 
	; 03/12/2020 (TRDOS 386 v2.0.3)
	; 13/05/2016
	; 30/01/2016
	; 24/01/2016
	; 04/01/2016
	movzx	ebx, byte [ACTIVE_PAGE] ; video page number (0 to 7)
	mov 	ah, [ebx+vmode] ; default = 03h (80x25 text)
	cmp	ah, 4
	jb	short cls1
	cmp	ah, 7
	jne	short vga_clear
cls1:
	;mov	bh, bl
	;mov	bl, 7
	cmp	ah, [CRT_MODE] ; current video mode ? 
	je	short cls2 ; yes (current video mode = 3)
	;;call	set_mode_3 ; set video mode to 3 (& clear screen)
	;;retn
	; 06/12/2020
	cmp	byte [pmi32], 0
	ja	short vga_clear 	
	jmp	set_mode_3
cls2:
	mov	bh, bl ; video page (0 to 7)
	mov	bl, 07h ; attribute to be used on blanked line
	sub 	al, al ; 0 =  entire window
	xor 	cx, cx
	mov 	dx, 184Fh
	call	_scroll_up ; 24/01/2016
	;
	;mov	bh, [ACTIVE_PAGE] ; video page number (0 to 7)
	xor 	dx, dx
	;call	_set_cpos ; 24/01/2016 
	;;retn
	; 03/12/2020
	jmp	_set_cpos ; returns to the caller of this proc
;cls3:
;	retn
	; 06/12/2020
vga_clear:
	; 03/12/2020
	; set mode by using _int10h
	; (also clears screen)
	mov	al, ah
	sub	ah, ah  ; set current video mode
	;call	_int10h ; simulates int 10h in TRDOS 386 kernel
	;jmp	short cls3
	jmp	_int10h ; returns to the caller of this proc

panic:
	; 13/05/2016 (TRDOS 386 = TRDOS v2)
	; 13/03/2015 (Retro UNIX 386 v1)
	; 07/03/2014 (Retro UNIX 8086 v1)
	mov 	esi, panic_msg
	call 	print_msg
key_to_reboot:
        ; 24/01/2016
        sub     ah, ah
        call    int16h ; call   getch
        ; wait for a character from the current tty
	;
	mov	al, 0Ah
	mov	bh, [ptty] ; [ACTIVE_PAGE]
	mov	bl, 07h ; Black background, 
			; light gray forecolor
	call 	_write_tty
	jmp	cpu_reset 

ctrlbrk:
	; 12/11/2015
	; 13/03/2015 (Retro UNIX 386 v1)
	; 06/12/2013 (Retro UNIX 8086 v1)
	;
	; INT 1Bh (control+break) handler		
	;
      	; Retro Unix 8086 v1 feature only!
      	;
	cmp 	word [u.intr], 0
	jna 	short cbrk4
cbrk0:
	; 12/11/2015
	; 06/12/2013
	cmp 	word [u.quit], 0
	jz	short cbrk4
	;
	; 20/09/2013	
	push 	ax
	mov	al, [ptty]
	;
	; 12/11/2015
	;
	; ctrl+break (EOT, CTRL+D) from serial port
	; or ctrl+break from console (pseudo) tty
	; (!redirection!)
	;
	cmp	al, 8 ; serial port tty nums > 7
        jb      short cbrk1 ; console (pseudo) tty
	;	
	; Serial port interrupt handler sets [ptty]
	; to the port's tty number (as temporary).
	;
	; If active process is using a stdin or 
	; stdout redirection (by the shell),
        ; console tty keyboard must be available
	; to terminate running process,
	; in order to prevent a deadlock. 
	;
	push	edx
	movzx	edx, byte [u.uno]
	cmp     al, [edx+p.ttyc-1] ; console tty (rw)
	pop	edx
	je	short cbrk2
cbrk1:
	inc 	al  ; [u.ttyp] : 1 based tty number
	; 06/12/2013
	cmp	al, [u.ttyp] ; recent open tty (r)
	je	short cbrk2	
        cmp     al, [u.ttyp+1] ; recent open tty (w)
	jne	short cbrk3	
cbrk2:
	;; 06/12/2013
	;mov	ax, [u.quit]
	;and	ax, ax
	;jz	short cbrk3
	;
	xor	ax, ax ; 0
	dec	ax
	; 0FFFFh = 'ctrl+brk' keystroke
	mov	[u.quit], ax
cbrk3:
	pop	ax
cbrk4:
	retn


; 31/12/2017
; TRDOS 386 - 30/12/2017
%define get_rtc_date RTC_40
%define get_rtc_time RTC_20
%define	set_rtc_date RTC_50
%define set_rtc_time RTC_30	
get_rtc_date_time:
; Retro UNIX 8086 v1 - UNIX.ASM (01/09/2014)
;epoch:
	; 30/12/2017 (TRDOS 386 = TRDOS v2.0)
	; 15/03/2015 (Retro UNIX 386 v1 - 32 bit version)
	; 09/04/2013 (Retro UNIX 8086 v1 - UNIX.ASM)
	; 'epoch' procedure prototype: 
	; 	            UNIXCOPY.ASM, 10/03/2013
	; 14/11/2012
	; unixboot.asm (boot file configuration)
	; version of "epoch" procedure in "unixproc.asm"
	; 21/7/2012
	; 15/7/2012
	; 14/7/2012		
	; Erdogan Tan - RETRO UNIX v0.1
	; compute current date and time as UNIX Epoch/Time
	; UNIX Epoch: seconds since 1/1/1970 00:00:00
	;
        ;  ((Modified registers: EAX, EDX, ECX, EBX))  
	;

	call 	get_rtc_time		; Return Current Time
        xchg 	ch,cl
        mov 	[hour], cx
        xchg 	dh,dl
        mov 	[second], dx
	;
        call 	get_rtc_date		; Return Current Date
        xchg 	ch,cl
        mov 	[year], cx
        xchg 	dh,dl
        mov 	[month], dx
	;
	mov 	cx, 3030h
	;
	mov 	al, [hour] ; Hour
        	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	mov 	[hour], al
	mov 	al, [hour+1] ; Minute
        	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	mov 	[minute], al
	mov 	al, [second] ; Second
        	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	mov 	[second], al
	mov 	ax, [year] ; Year (century)
        push 	ax
	   	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	mov 	ah, 100
	mul 	ah
	mov 	[year], ax
	pop	ax
	mov	al, ah
        	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	add 	[year], ax
	mov 	al, [month] ; Month
           	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
	mov 	[month], al	
        mov     al, [month+1]      	; Day
           	; AL <= BCD number)
        db 	0D4h,10h		; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad 	; AX= AH*10+AL
        mov     [day], al
	
	retn	; 30/12/2017

epoch:
	call	get_rtc_date_time ; TRDOS 386 - 30/12/2017

convert_to_epoch:
	; 31/12/2017 (TRDOS 386 = TRDOS v2.0)
	; 15/03/2015 (Retro UNIX 386 v1 - 32 bit modification)
	; 09/04/2013 (Retro UNIX 8086 v1)
	;
	; ((Modified registers: EAX, EDX, EBX)) 
	;
	; Derived from DALLAS Semiconductor
	; Application Note 31 (DS1602/DS1603)
	; 6 May 1998
	sub 	eax, eax
	mov 	ax, [year]
	sub 	ax, 1970
	mov 	edx, 365
	mul 	edx
	xor 	ebx, ebx
	mov 	bl, [month]
	dec 	bl
	shl 	bl, 1
	;sub	edx, edx
	mov 	dx, [EBX+DMonth]
        mov     bl, [day]
	dec 	bl
	add 	eax, edx
	add 	eax, ebx
			; EAX = days since 1/1/1970
	mov 	dx, [year]
	sub 	dx, 1969
	shr 	dx, 1
	shr 	dx, 1		
		; (year-1969)/4
	add 	eax, edx
			; + leap days since 1/1/1970
	cmp 	byte [month], 2	; if past february
	jna 	short cte1
	mov 	dx, [year]
	and 	dx, 3 ; year mod 4
	jnz 	short cte1		
			; and if leap year
	add 	eax, 1 	; add this year's leap day (february 29)
cte1: 			; compute seconds since 1/1/1970
	mov 	edx, 24
	mul	edx
	mov 	dl, [hour]
	add 	eax, edx
		; EAX = hours since 1/1/1970 00:00:00
	;mov	ebx, 60
	mov	bl, 60
	mul	ebx
	mov 	dl, [minute]
	add 	eax, edx
		; EAX = minutes since 1/1/1970 00:00:00
	;mov 	ebx, 60
	mul	ebx
	mov 	dl, [second]
	add 	eax, edx
 		; EAX -> seconds since 1/1/1970 00:00:00
	retn

;set_date_time:
convert_from_epoch:
	; 31/12/2017 (v2.0.0)
	; 30/12/2017 (TRDOS 386 = TRDOS v2.0)
	; 15/03/2015 (Retro UNIX 386 v1 - 32 bit version)
	; 20/06/2013 (Retro UNIX 8086 v1)
	; 'convert_from_epoch' procedure prototype: 
	; 	            UNIXCOPY.ASM, 10/03/2013
	;
	; ((Modified registers: EAX, EDX, ECX, EBX))	
	;
	; Derived from DALLAS Semiconductor
	; Application Note 31 (DS1602/DS1603)
	; 6 May 1998
	;
	; INPUT:
	; EAX = Unix (Epoch) Time
	;
	xor 	edx, edx
	mov 	ecx, 60
	div	ecx
	;mov 	[imin], eax   ; whole minutes
			  ; since 1/1/1970
	mov 	[second], dx  ; leftover seconds
	sub 	edx, edx
	div	ecx
	;mov 	[ihrs], eax   ; whole hours
	;		      ; since 1/1/1970
	mov 	[minute], dx  ; leftover minutes
	xor	edx, edx
	;mov 	cx, 24
	mov 	cl, 24
	div	ecx
	;mov 	[iday], ax   ; whole days
			     ; since 1/1/1970
	mov 	[hour], dx   ; leftover hours
	add 	eax, 365+366 ; whole day since
			     ; 1/1/1968 	
	;mov 	[iday], ax
	push 	eax
	sub	edx, edx
	mov 	ecx, (4*365)+1 ; 4 years = 1461 days
	div	ecx
	pop 	ecx
	;mov 	[lday], ax   ; count of quadyrs (4 years)
	push 	dx
	;mov 	[qday], dx   ; days since quadyr began
	cmp 	dx, 31 + 29  ; if past feb 29 then
	cmc		     ; add this quadyr's leap day
	adc 	eax, 0	     ; to # of qadyrs (leap days)
	;mov 	[lday], ax   ; since 1968			  
	;mov 	cx, [iday]
	xchg 	ecx, eax     ; ECX = lday, EAX = iday		  
	sub 	eax, ecx     ; iday - lday
	mov 	ecx, 365
	xor	edx, edx
	; EAX = iday-lday, EDX = 0
	div	ecx
	;mov 	[iyrs], ax   ; whole years since 1968
	;jday = iday - (iyrs*365) - lday
	;mov [jday], dx      ; days since 1/1 of current year
	;add	eax, 1968
	add 	ax, 1968     ; compute year
	mov 	[year], ax
	mov 	cx, dx
	;mov 	dx, [qday]
	pop 	dx
	cmp 	dx, 365	     ; if qday <= 365 and qday >= 60	
	ja 	short cfe1   ; jday = jday +1
	cmp 	dx, 60       ; if past 2/29 and leap year then
        cmc		     ; add a leap day to the # of whole
	adc 	cx, 0        ; days since 1/1 of current year
cfe1:			
	;mov 	[jday], cx
	mov 	bx, 12       ; estimate month
	mov 	dx, 366      ; mday, max. days since 1/1 is 365
	and 	ax, 11b      ; year mod 4 (and dx, 3) 
cfe2:	; Month calculation  ; 0 to 11  (11 to 0)	
	cmp 	cx, dx       ; mday = # of days passed from 1/1
	jnb 	short cfe3
	dec 	bx           ; month = month - 1
	shl 	bx, 1 
	mov 	dx, [EBX+DMonth] ; # elapsed days at 1st of month
	shr 	bx, 1        ; bx = month - 1 (0 to 11)
	cmp	bx, 1        ; if month > 2 and year mod 4  = 0	
	jna 	short cfe2   ; then mday = mday + 1
	or 	al, al       ; if past 2/29 and leap year then
	jnz 	short cfe2   ; add leap day (to mday)
	inc 	dx           ; mday = mday + 1
	jmp 	short cfe2
cfe3:
	inc 	bx	     ; -> bx = month, 1 to 12
	mov 	[month], bx
	sub 	cx, dx	     ; day = jday - mday + 1	
	inc 	cx 			  
	mov 	[day], cx
	
	; eax, ebx, ecx, edx is changed at return
	; output ->
	; [year], [month], [day], [hour], [minute], [second]

	retn	; 31/12/2017 (TRDOS 386)

set_rtc_date_time:
	; 31/12/2017 (v2.0.0)
	; 30/12/2017 (TRDOS 386)
	; 15/03/2015 (Retro UNIX 386 v1 - 32 bit version)
	; 20/06/2013 (Retro UNIX 8086 v1)
	call	set_date_bcd
	; Set real-time clock date
	call	set_rtc_date ; RTC_50
	; Set real-time clock time
	call	set_time_bcd
	jmp	set_rtc_time ; RTC_30	

; 31/12/2017
set_date_bcd:
        mov     al, [year+1]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	ch, al ; century (BCD)
	mov 	al, [year]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	cl, al ; year (BCD)
        mov 	al, [month]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	dh, al ; month (BCD)
	mov 	al, [day]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	dh, al ; day (BCD)
	retn	; 30/12/2017

; 31/12/2017
set_time_bcd:
        ; Read real-time clock time 
	; (get day light saving time bit status)
 	cli
	CALL	UPD_IPR 		; CHECK FOR UPDATE IN PROCESS
	; cf = 1 -> al = 0
        jc      short stime1
	MOV	AL,CMOS_REG_B		; ADDRESS ALARM REGISTER
	CALL	CMOS_READ		; READ CURRENT VALUE OF DSE BIT
stime1:
	sti
	AND	AL,00000001B		; MASK FOR VALID DSE BIT
	MOV	DL,AL			; SET [DL] TO ZERO FOR NO DSE BIT
	; DL = 1 or 0 (day light saving time)
	;	
	mov 	al, [hour]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	ch, al ; hour (BCD)
        mov     al, [minute]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	cl, al       ; minute (BCD)
        mov     al, [second]
	aam 	; ah = al / 10, al = al mod 10
	db 	0D5h,10h     ; Undocumented inst. AAD
			     ; AL = AH * 10h + AL
	mov 	dh, al	     ; second (BCD)
	retn	; 30/12/2017
