; ****************************************************************************
;
; UNIXBOOT.ASM (Only for 1.44 MB floppy disks)
; ----------------------------------------------------------------------------
;
; RETRO UNIX 8086 (Retro Unix == Turkish Rational Unix)
; Operating System Project (v0.1) by ERDOGAN TAN (Beginning: 11/07/2012) 
; 1.44 MB Floppy Disk 
; Bootable Unix (RUFS) File System - Boot File Configuration Code
;
; [ Last Modification: 09/07/2013 ]
;
; Derivation from UNIX Operating System (v1.0 for PDP-11) 
; (Original) Source Code by Ken Thompson (1971-1972)
; <Bell Laboratories (17/3/1972)>
; <Preliminary Release of UNIX Implementation Document>
;
; Derived from (Only for 1.44 MB floppy disks)
; SINGLIX FS startup file configuration utility, BOOTFILE.ASM (21/02/2010)
;
; ****************************************************************************

bsFSystemID 	equ 2  ; 'RUFS'	
bsVolumeSerial 	equ 6  ; (4 bytes)
bsFDSign	equ 10 ; 'fd'
bsDriveNumber 	equ 12 ; fd0 or fd1 (0 or 1)
bsReserved 	equ 13 ; 0 (512 bytes per sector)	
bsSecPerTrack	equ 14 ; 18 (9 or 15)	
bsHeads		equ 15 ; 2
bsTracks	equ 16 ; 80
bs_BF_inode_number	equ 18 ; 0 or Boot/Startup File I-Number
bsInfoEndsign	equ 20 ; '@'

ROOT_DIR_INODE_NUMBER equ 41

; DTA (PSP+80h= Offset 128)
DTA_Time equ 150 ; PSP+22
DTA_Date equ 152 ; PSP 24
DTA_FileSize equ 154 ; PSP + 26
DTA_FileName equ 158 ; PSP + 30


err_INVALIDDATA equ 100h
err_NOFREEBLOCK equ 200h

i_flags		equ 001Eh

.8086

UNIXBOOT     SEGMENT PUBLIC 'CODE'
                assume cs:UNIXBOOT,ds:UNIXBOOT,es:UNIXBOOT,ss:UNIXBOOT

                org 100h

START_CODE:

proc_start      proc near
		; 30/11/2012
		; 18/11/2012
		; 31/10/2012
                mov bx, SizeOfFile+100
                add bx, 15
                shr bx, 1
        	shr bx, 1
		shr bx, 1
		shr bx, 1
                mov ah, 4Ah ; modify memory allocation
               ;push cs
               ;pop es
                int 21h 
                                  
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; see if drive specified
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
              
                mov si, offset 80h                      ; PSP command tail
                mov cl, byte ptr [SI]
                or cl, cl                               
                jz loc_unix_welcome        ; jump if zero
loc_get_args:
                inc si
                mov al, byte ptr [SI]
                cmp al, ' '                      ; is it SPACE ?
                jne short loc_check_fd_name

                dec cl                                  
                jnz short loc_get_args                
                
                jmp loc_unix_welcome

loc_check_fd_name:
                cmp al, "f"
                jne loc_unix_welcome
                inc si
                mov al, byte ptr [SI]
                cmp al, "d"
                jne short loc_unix_welcome
                inc si
                mov al, byte ptr [SI]
                cmp al, '0'                            
                jb short loc_unix_welcome
                cmp al, '1'
                ja short loc_unix_welcome
                mov byte ptr [UNIX_FD_Number], al
                mov dl, al
                sub dl, '0'
                mov byte ptr [PhysicalDriveNumber], dl

load_boot_sector: ; 11/11/2012
                ; input -> dl = drive number
                xor ah,ah
                int 13h
                jc short loc_drv_read_error

load_boot_sector_ok:
                mov bx, offset BSBuffer
                mov ax,0202h  ; Read boot sector & super block, 17/11/2012
                mov cx,1
                xor dh,dh
                int 13h
                jc short loc_drv_read_error

 		cmp word ptr [BX]+510, 0AA55h
                jne  short loc_not_fd_rufs

                cmp word ptr [BX]+bsFSystemID, 'UR'
                jne  short loc_not_fd_rufs

		cmp word ptr [BX]+bsFSystemID+2, 'SF'
		je short loc_check_fd_sign

loc_not_fd_rufs:
                mov si, offset msg_Not_Unix_FS
		jmp short @f		

loc_check_fd_sign:
		cmp word ptr [BX]+bsFDSign, 'df'
		jne short loc_not_fd_rufs
 
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Write message
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

loc_dywtw_question::
                mov si, offset Msg_DoYouWantToWrite
                call UNIX_PRINTMSG
               
                mov si, offset UNIX_FD_Name
                call UNIX_PRINTMSG

loc_print_yes_no: 
		mov si, offset msg_yes_no
                call UNIX_PRINTMSG
loc_ask_for_write_sf:
                xor ax, ax
                int 16h                                 ; wait for keyboard command
                cmp al, 'C'-40h
                je short @f                   
                cmp al, 27
                je short @f
                and al, 0DFh
                cmp al, 'Y'                             ; Yes?
                je short loc_yes_write_sf               ; write
                cmp al, 'N'                             ; No?
                jne short loc_ask_for_write_sf          

loc_no_write_sf:
                mov si, offset msg_No
                jmp short @f

loc_unix_welcome:
                mov si, offset UNIX_Welcome
@@:
                call UNIX_PRINTMSG

		int 20h
		
		int 19h

loc_drv_read_error:
                mov si, offset msg_unix_drv_read_error

		jmp short @b

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; get drive parameters
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

loc_yes_write_sf:
                mov si, offset msg_YES
                call UNIX_PRINTMSG

loc_load_fs_boot_sector:
                mov si, offset BSBuffer
loc_check_current_sbf_adress:
                mov ax, word ptr [SI]+bs_BF_inode_Number
	        or ax, ax
                jnz short loc_startup_file_exists

loc_dos_sf_name_input:
                mov si, offset Msg_DosFile_Name
                call UNIX_PRINTMSG
		mov al, 64  ; DOS file name (max.) length (for full path name)	
                call proc_rw_char
                jc short pass_write_file_name_chr0
                mov di, offset StartupFile_Name
                cmp byte ptr [SI], 20h
                jna short pass_write_file_name_chr0
                mov cx, 64
loc_write_file_name_chr0:
                lodsb
                cmp al, 20h
                jnb short loc_write_file_name_chr1 
pass_write_file_name_chr0:
                mov byte ptr [DI], 0
                inc di
                loop pass_write_file_name_chr0
                jmp short loc_find_dos_file
loc_write_file_name_chr1:
                mov byte ptr [DI], al
                inc di
                loop loc_write_file_name_chr0
loc_find_dos_file:
		mov si, offset UNIX_CRLF
 		call UNIX_PRINTMSG
                mov dx, offset StartupFile_Name
                mov cx, 27h ; File Attributes
                mov ah, 4Eh ; MS Dos Function = Find First File
                int 21h
                jnc loc_open_dos_file_1

                jmp loc_dos_file_notfound

loc_startup_file_exists:
		; AX = Startup/Boot File I-Number
		;
		; 25/11/2012
		;mov bx, ax
		;;mov cx, 9
		;mov cx, 4
		;mov di, offset Boot_File_Name
		;xor al, al
		;;xor ax, ax
		;rep stosb
		;;rep stosw
		
		; ax= i-number
		call find_bfn
		jnc short loc_move_bfn_1

		and ax, ax
		jnz short loc_drv_read_error

		;mov si, offset BSBuffer
		;mov  word ptr [SI]+bs_BF_inode_Number, ax
		; jmp short loc_dos_sf_name_input

loc_move_bfn_1:
		mov si, offset u_dirbuf + 2
		mov di, offset Boot_File_Name
		mov cx, 8
loc_move_bfn_2:
                lodsb
                and al, al
		jnz short @f
		mov byte ptr [DI], al ; 0
		
		;cmp al, 20h
                ;;jb short loc_startup_file_exists_msg
		;;ja short @f
		;mov byte ptr [DI], 0

		jmp short loc_startup_file_exists_msg
@@:
                stosb
                loop loc_move_bfn_2

loc_startup_file_exists_msg:
		mov si, offset msg_Startup_file_exists
                call UNIX_PRINTMSG
                
loc_startup_file_exist_select_option:
		; 25/11/2012
                xor ah, ah
                int 16h
                cmp al, 1Bh
                je loc_exit
                cmp al, 0Dh
                jne short loc_check_startupfile_delete_decision

                call proc_display_startupfile_info

                mov si, offset msg_please_select_an_option

                call UNIX_PRINTMSG
                jmp short loc_startup_file_exist_select_option 
   
loc_check_startupfile_delete_decision:
                cmp ah, 53h
                jne short loc_startup_file_exist_select_option

loc_delete_decision_second_stage:
		; 01/12/2012
		mov si, offset msg_Delete_Startup_File
                call UNIX_PRINTMSG

		mov bx, offset BSBuffer
		xor cx, cx

loc_delete_startup_file_input:
 		xor ah, ah
                int 16h
                cmp al, 1Bh
                je loc_exit
		cmp al, 0Dh
		je short loc_reset_startupfile_configuration
                cmp ah, 53h
                jne short loc_delete_startup_file_input

loc_delete_startup_file:
		mov ax, word ptr [BX]+bs_BF_inode_Number
		mov word ptr [BX]+bs_BF_inode_Number, cx
		push ax	
		mov si, offset Msg_deleting_sf
		call UNIX_PRINTMSG
		pop ax
		call unlink ; delete file	
                jc loc_unix_fd_write_error

		jmp loc_update_boot_sector_and_sb
                
loc_reset_startupfile_configuration:
		mov word ptr [bx]+bs_BF_inode_Number, cx
		mov ax,0301h  ; Write boot sector
        	;mov cx,1
		inc cx
        	xor dh,dh
		mov dl, byte ptr [PhysicalDriveNumber]
        	int 13h
                jc loc_unix_fd_write_error
		mov si, offset msg_sf_configuration_reset_ok
		call UNIX_PRINTMSG
		jmp loc_exit
		
loc_open_dos_file_1:
                mov si, DTA_FileName
                mov di, offset StartupFile_Name
                mov cx, 64
loc_copy_found_file_name_chr0:
                lodsb
                cmp al, 20h
                jnb short loc_copy_found_file_name_chr1 
pass_copy_found_file_name_chr0:
                mov byte ptr [DI], 0
                inc di
                loop pass_copy_found_file_name_chr0
                jmp short loc_set_startupfile_inode
loc_copy_found_file_name_chr1:
                mov byte ptr [DI], al
                inc di
                loop loc_copy_found_file_name_chr0

loc_set_startupfile_inode:
		; 30/11/2012 BugFix
		;
		; DOS TimeStamp ->
		;  Bits 0-4 seconds/2
		;  Bits 5-10 minute
		;  Bits 11-15 hour
		; DOS DateStamp ->
	 	;  Bits 0-4 (16-20) day
		;  Bits 5-8 (21-24) month
		;  Bits 9-15 (25-31) year
		;	 
		; 25/11/2012 modification
		;mov 	word ptr [inode_flgs], 801Eh ; 1000000000011110b
		;mov 	byte ptr [inode_nlnks], 1
		;mov	byte ptr [inode_uid], 0
		
		;xor 	ax, ax	
		;mov	cx, 8
		;mov	di, offset inode_dskp
		;rep	stosw
		
                mov 	si, DTA_FileSize
                mov     ax, word ptr [SI]
                mov 	dx, word ptr [SI]+2
		or 	dx, dx
                jnz     loc_very_big_startupfile_size

		mov 	word ptr [inode_Size], ax

		mov     si, DTA_Date
                mov 	ax, word ptr [SI]
                push 	ax
                and 	ax, 00011111b	         ; Day Mask
		mov 	word ptr [day], ax
                pop 	ax
     		mov     cl, 5
		shr     ax, cl                   ; shift right 5 times
	        push 	ax 
		and     ax, 00001111b            ; Month Mask
  		mov 	word ptr [month], ax
                pop 	ax
		mov     cl, 4
		shr     ax, cl
	       ;and     ax, 01111111b            ; Result = Year - 1980
                add     ax, 1980
                mov     word ptr [year], ax
 		                
                mov     si, DTA_Time
                mov 	ax, word ptr [SI]
                push 	ax
		and     ax, 0000011111b          ; Second Mask
		shl 	al, 1		 
		mov     word ptr [second], ax
                pop 	ax
		mov     cl, 5
		shr     ax, cl                   ; shift right 5 times
		push	ax
		and     ax, 0000111111b          ; Minute Mask
		mov     word ptr [minute], ax
                pop 	ax
		mov	cl, 6			 ; shift right 6 times
                shr     ax, cl                   ; (6+5=11)
		mov     word ptr [hour], ax	 ; ax = hours	
           
                call convert_to_epoch

		mov word ptr [bf_make_datetime], ax
		mov word ptr [bf_make_datetime]+2, dx

loc_open_dos_file_2:
		mov dx, offset StartupFile_Name
                mov ah, 3Dh ; MS Dos Function = Open File
                xor al, al  
                int 21h
                jnc short loc_save_filehandle

loc_dos_file_notfound:
                mov si, offset Msg_File_Not_Found
                call UNIX_PRINTMSG

                jmp loc_exit

loc_very_big_startupfile_size:
		mov si, offset msg_very_big_startup_file_size
                call UNIX_PRINTMSG
                jmp loc_exit

loc_save_filehandle:
		mov word ptr [FileHandle], ax
loc_display_startup_file_name:
                mov si, offset Msg_StartupFile_Name
                call UNIX_PRINTMSG
                ;mov ah, 03h
               ;;xor bh, bh
                ;int 10h
               ;;push dx         
                ;mov si, offset StartupFile_Name
                ;call UNIX_PRINTMSG
               ;;pop dx
                ;mov ah, 02h
               ;;xor bh, bh
                ;int 10h
		mov al, 8  ; Boot file name (max.) length (unix v1 fs)	
		call proc_rw_char
                jc loc_exit
                cmp byte ptr [SI], 20h
                jna loc_exit
                mov di, offset BOOT_FILE_NAME
		mov word ptr [u_namep], di ; 11/11/2012
                mov cx, 8
loc_rename_file_name_chr0:
                lodsb
                cmp al, 20h
                jnb short loc_rename_file_name_chr1 
pass_rename_file_name_chr0:
                mov byte ptr [DI], 0
                inc di
                loop pass_rename_file_name_chr0
                jmp short loc_check_startupfile_name

loc_rename_file_name_chr1:
                mov byte ptr [DI], al
                inc di
                loop loc_rename_file_name_chr0

loc_check_startupfile_name:
                mov si, offset UNIX_CRLF
 		call UNIX_PRINTMSG
                
		call name_i  ;11/11/2012
                jc short loc_check_namei_error ; 1/12/2012

		; 1/12/2012
		push ax  ; i-number of file

		mov si, offset msg_overwrite_question1
		call UNIX_PRINTMSG
		mov si, offset BOOT_FILE_NAME
		call UNIX_PRINTMSG
		mov si, offset msg_overwrite_question2
		call UNIX_PRINTMSG
		mov si, offset msg_yes_no
		call UNIX_PRINTMSG			

loc_ask_for_overwrite_f:
                xor ax, ax
                int 16h                                 ; wait for keyboard command
                cmp al, 'C'-40h
                je short @f                   
                cmp al, 27
                je short @f
                and al, 0DFh
                cmp al, 'Y'                             ; Yes?
                je short loc_yes_overwrite_f               ; write
                cmp al, 'N'                             ; No?
                jne short loc_ask_for_overwrite_f          

loc_no_ovewrite_f:
		pop ax   	
	        mov si, offset msg_No
@@:
                mov ah, 3Eh ; Close File
                mov bx, word ptr [FileHandle]
                int 21h
		jmp loc_exit

loc_yes_overwrite_f:
                mov si, offset msg_YES
                call UNIX_PRINTMSG

                mov si, offset UNIX_CRLF
                call UNIX_PRINTMSG

		pop ax  ; i-number of file

		call itrunc ; truncate file
		jc short loc_unix_fd_write_error

                mov si, offset Msg_writing_sf
                call UNIX_PRINTMSG

		mov ax, word ptr [ii]
		jmp short @f

loc_check_namei_error:		
		cmp ah, 0FFh
                jne short loc_close_dos_sf ; jb / cf = 1
loc_write_SF:
                mov si, offset Msg_writing_sf
                call UNIX_PRINTMSG
loc_make_inode:
		mov ax, i_flags ; Boot file flags, 001Eh
		call mak_nod
		jc short loc_unix_fd_write_error
@@:
		mov bx, offset BSBuffer
		mov word ptr [BX]+ bs_BF_inode_Number, ax ; i-number

		xor ax, ax 
	        mov word ptr [u_off], ax
 	       ;mov word ptr [u_fofp], offset u_off		

loc_read_dos_sf:                
                mov ah, 3Fh ; Read File
                mov cx, 512
                mov dx, offset ReadBUFFER
                mov bx, word ptr [FileHandle]
                int 21h
                jc short loc_close_dos_sf

		or ax, ax
		jz short loc_close_dos_sf
		
		mov word ptr [u_count], ax

		mov word ptr [u_base], offset ReadBuffer

		mov ax, word ptr [u_dirbuf]
		call write_i
		jnc short loc_read_dos_sf

 		jmp short loc_unix_fd_write_error

loc_close_dos_sf:
	        pushf
                mov ah, 3Eh ; Close File
                mov bx, word ptr [FileHandle]
                int 21h
                popf 
                jc loc_drv_read_error

loc_update_boot_sector_and_sb:
		; 18/11/2012
		call sync
                jc short loc_unix_fd_write_error

loc_write_SF_ok:
                mov si, offset Msg_OK
                call UNIX_PRINTMSG

                mov si, offset UNIX_CRLF
                call UNIX_PRINTMSG
loc_exit:
                int 20h
                
                int 19h
 
loc_unix_fd_write_error: 
		mov ah, 3Eh ; Close File
                mov bx, word ptr [FileHandle]
                int 21h
 
                mov si, offset msg_unix_drv_write_error
                call UNIX_PRINTMSG
                jmp short loc_exit

proc_start     endp

UNIX_PRINTMSG     proc near
 
UNIX_PRINTMSG_LOOP:
                lodsb                           ; Load byte at DS:SI to AL
                and     AL,AL            
                jz      short UNIX_PRINTMSG_OK       
                mov     AH,0Eh                  
                mov     BX,07h             
                int     10h                     ; BIOS Service func ( ah ) = 0Eh
                                                ; Write char as TTY
                                                ;AL-char BH-page BL-color
                jmp     short UNIX_PRINTMSG_LOOP           

UNIX_PRINTMSG_OK:
                retn

UNIX_PRINTMSG     endp

proc_rw_char   proc    near
               ; OUTPUT -> DS:SI = Entered String (ASCIIZ)
               mov     si, offset StartupFile_Name
               mov     bx,7
               mov     ah,3
               int     10h
               mov     Word Ptr [Cursor_Pos], dx
read_next_char:
               xor     ah,ah
               int     16h
               and     al,al
               jz      short loc_arrow    
               cmp     al,0E0h          
               je      short loc_arrow
               cmp     al,08h
               jne     short char_return
loc_back:
               mov     bl,7
               mov     ah,3
               int     10h
               cmp     dl,byte ptr [Cursor_Pos]
               ja      short prev_column
loc_beep:
               mov     ah, 0Eh
               mov     al, 7
               int     10h
               jmp     short read_next_char
prev_column:
               dec     dl
set_cursor_pos:
               mov     ah,02h
               int     10h
               mov     bl, dl
               sub     bl,byte ptr [Cursor_Pos] 
               mov     cx,1
               mov     ah,09h
               mov     al,20h
               mov     byte ptr [SI][BX],al
loc_write_it:
               mov     bl,7
               int     10h
               mov     dx,word ptr [Cursor_Pos]
               jmp     short read_next_char
loc_arrow:    
               cmp     AH,4Bh
               je      short loc_back
               cmp     AH,53h
               je      short loc_back
               jmp     short read_next_char
char_return:
               mov     bl,7
               mov     ah,3
               int     10h
               mov     ah,dl
               sub     ah,byte ptr [Cursor_Pos] 
               cmp     al,20h
               jb      short loc_escape
               cmp     ah,63
               ja      short loc_beep
             ; cmp     al, "z"
             ; ja      short read_next_char
             ; cmp     al, "a"
             ; jb      short pass_capitalize
             ; and     al, 0DFh
pass_capitalize:
	       mov     bl, ah	
               xor     ah, ah
               mov     word ptr [SI][BX],ax
               mov     ah, 0Eh
               mov     bl, 7
               int     10h
               jmp     short read_next_char
pass_escape:
               cmp     al,0Dh
               jne     short read_next_char
               mov     bl,7
               int     10h
               mov     al,0Ah
               int     10h
               retn
loc_escape:
               cmp     al,1Bh
               jne     short pass_escape
               stc
               retn

proc_rw_char   endp


name_i proc near
	; 11/11/2012 unixboot.asm
	;  	     Unix boot file configuration version
	; 20/10/2012
	; 14/10/2012
	; Boot sector version of "namei" procedure
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;
	; RETRO UNIX v1 FS
	; Boot sector version
	;
	; return i-number of file (ax)
	;

	mov ax, ROOT_DIR_INODE_NUMBER ; 41
	call i_get
	jc short name_inode_retn

	test word ptr [inode_flgs], 4000h ; directory i-node ?
	jnz short @f

	mov ah, 0FFh ; error number
	stc
	jmp short name_inode_retn
@@:
	mov ax, word ptr [inode_size]  ; 11/11/2012 Unix boot file configuration version
	mov word ptr [u_dirp], ax  ; 11/11/2012 Unix boot file configuration version

	xor ax, ax 
	mov word ptr [u_off], ax ; u_off is file offset used by user

name_inode_1:
	mov word ptr [u_base], offset u_dirbuf
				  ; u.dirbuff holds a file name copied from
				  ; a directory	
	mov word ptr [u_count], 10 	
 	
	mov ax, ROOT_DIR_INODE_NUMBER 

	call read_i ; read 10 bytes of file with i-number
		   ; i.e. read a directory entry
	jc short name_inode_4
	
	mov cx, word ptr [u_nread]

	or cx, cx
	jna short name_inode_3 ; gives error return 

; 11/11/2012
; Unix boot file configuration version
;;;
	mov bx, word ptr [u_dirbuf]
	and bx, bx                    ; Check i-number of directory entry
	jnz short name_inode_2	      ; >0 means an active directory entry
	
	mov ax, word ptr [u_off]
	sub ax, 10
	mov word ptr [u_dirp], ax
	jmp short name_inode_1
;;;

name_inode_2:
	mov si, offset BOOT_FILE_NAME ; 
	mov di, offset u_dirbuf + 2 ; points to file name of directory entry
	mov dx, offset u_dirbuf + 10
@@:
	lodsb  ; mov al, byte ptr [SI], inc si
	scasb		      ; compare char in boot file name to file name char
			      ; read from directory; brach if chars match
	jne short short name_inode_1    
			      ;  File names do not match, go to next directory entry 
 	or al, al
	jz short name_inode_retn  ; If char is nul, then the last char in string has
			      ; been compared

	cmp di, dx
			      ; have i checked all 8 bytes of file name
	jna short @b 	      ; 

name_inode_retn:
	mov ax, word ptr [u_dirbuf] ; 20/10/2012, ax = i-number of the boot file

	retn

	;jmp short name_inode_retn   ; File names match
			  
name_inode_3:
	mov ah, 0FFh ; Error code
	
	stc

name_inode_4:
	retn
	
name_i 	endp


read_i proc near
	; 01/03/2013
	; 14/10/2012
	; Boot sector version of "readi" procedure
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;;AX (R1) = i-number 
	; RETRO UNIX v1 FS
	; Boot sector version
	;
	; read from an i-node
	;

	xor dx, dx ; 0
	mov word ptr [u_nread], dx ; accumulated number of bytes transmitted
	cmp word ptr [u_count], dx ; is number of byte to read greater than 0
	jna short read_inode_retn

read_inode_1:
	; AX = I-Number
	push ax
	call i_get ; get i-node into i-node section of core
	jc short read_inode_3 ; 01/03/2013
	mov dx, word ptr [inode_size] ; file size in bytes in r2 (DX)
	sub dx, word ptr [u_off] ; subtract file offset
	jna short read_inode_3
	cmp dx, word ptr [u_count] 
			; are enough bytes left in file to carry out read
	jnb short read_inode_2
	mov word ptr [u_count], dx

read_inode_2:
	call m_get  ; returns physical block number of block in file 
		   ; where offset points
	jc short read_inode_3 ; 01/03/2013
	; AX = Physical block number
	call dsk_rd ; read in block, BX points to 1st word of data in
		   ; buffer
	jc short read_inode_3

readinode_sioreg:
        mov si, word ptr [u_off] ; R2
	mov cx, si ; cx = R3, si = R2
	or cx, 0FE00h ; set bits 9...15 of file offset in R3
	and si, 1FFh ; calculate file offset mod 512
	add si, bx ; offset WriteBuffer ; si now points to 1st byte in buffer
		   ; where data is to be placed
        mov di, word ptr [u_base] ; R1
	neg cx ; 512 - file offset(mod512) in R3 (cx)
        cmp cx, word ptr [u_count]
	jna short @f ; 2f

        mov cx, word ptr [u_count]
@@:
	add word ptr [u_nread], cx ; r3 + number of bytes
			; xmitted during write is put into
                        ; u_nread
        sub word ptr [u_count], cx
        add word ptr [u_base], cx ; points to 1st of remaining
			; data bytes
        add word ptr [u_off], cx ; new file offset = number 
			; of bytes done + old file offset

; end of readinode_sioreg

	; DI = file (user data) offset
	; SI = sector (I/O) buffer offset
	; CX = byte count 

        rep movsb

	pop ax

	cmp word ptr [u_count], 0
	ja short read_inode_1

	retn

read_inode_3:	
	pop ax ; i-number

read_inode_retn:
	retn 

read_i 	endp


i_get 	proc near
	; 18/11/2012 unix boot file configuration version
	; of "iget" procedure.
	; 16/9/2012
     	; 14/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; AX=R1 
	; RETRO UNIX v1 FS
	;; return => if cf=1 error number in [Error]  

	cmp ax, word ptr [ii] ; AX (R1) = i-number of current file
	je short iget_4
iget_1:
	mov dl, byte ptr [imod]
	and dl, dl ; has i-node of current file been modified ?	
	jz short iget_2
	xor dl, dl ; mov al, 0
	mov byte ptr [imod], dl 
	push ax
	mov ax, word ptr [ii]	
	inc dl ; mov dl, 1
	; dl = 1 = write
	call i_calc
	pop dx
	jc short iget_4
	mov ax, dx
iget_2:
	and ax, ax
	jz short iget_3
	mov word ptr [ii], ax
	xor dl, dl		
	; dl = 0 = read
	call i_calc
iget_3:
	mov ax, word ptr [ii]
iget_4:
	retn

i_get	endp


i_calc 	proc near
	; 18/11/2012 unix boot file configuration version
	; of "icalc" procedure.
	; 17/8/2012
     	; 14/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; AX=R1
	; 0 = read, 1 = write
	; RETRO UNIX v1 FS
	;
        ; i-node is located in block (i+47)/16 and
	; begins 32*(i+47) mod 16 bytes from its start
	;; return => if cf=1 error number in [Error]

	; input -> dl = 0 -> read, 1 = Write

	mov byte ptr [rw], dl

	add ax, 47 ; add 47 to inode number
	push ax ; R1 -> -(SP)
	shr ax, 1 ; divide by 16
	shr ax, 1
	shr ax, 1
	shr ax, 1
		  ; ax contains block number of block in which
		  ; inode exists
	call dsk_rd
	pop dx
	jc short icalc_4

icalc_1:
	and dx, 0Fh	; (i+47) mod 16
	shl dx, 1
	shl dx, 1
	shl dx, 1
	shl dx, 1
	shl dx, 1 
		  ; DX = 32 * ((i+47) mod 16)	
                  ; DX (R5) points to first word in i-node i.

	mov di, offset inode
		; inode is address of first word of current inode
	mov cx, 16 ; CX = R3	

	mov si, offset WriteBuffer

	add si, dx

	cmp byte ptr [rw], 0
	jna short icalc_3 ; 0 = read (and copy i-node to memory) 

icalc_2:
	xchg si, di
	; over write old i-node (in buffer to be written)
	rep movsw

	mov ax, word ptr [buff_s] ; 18/11/2012

	call dsk_wr
      	
        retn 

icalc_3:
	; copy new i-node into inode area of (core) memory
	rep movsw

icalc_4:
	retn

i_calc 	endp


dsk_rd	proc near
	; 28/11/2012 BugFix 
	; 20/10/2012 (buff_s)
	; 14/10/2012
	; fd boot sector version of "dskrd" procedure
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	; RETRO UNIX v1 FS
	; floppy disk boot sector version
	;; return => if cf=1 error number in [Error]

	 ; ax = sector/block number

	 mov bx, offset WriteBuffer ; 28/11/2012

	 cmp ax, word ptr [buff_s] ; buffer sector
	 je short dsk_rd_3

	 mov si, ax

	 xor ch, ch
	 mov cl, 4 ; Retry count
dsk_rd_1:
         push  cx
         mov   dx, 18                  ; Sectors per track
         div   dl                      
         mov   cl, ah                  ; Sector (zero based)
         inc   cl                      ; To make it 1 based
         shr   al, 1		       ; Convert Track to Cylinder
         adc   dh, 0                   ; Heads (0 or 1)

         mov   dl, byte ptr [PhysicalDriveNumber] 
         mov   ch, al

	 mov   ah, 2 		       ; 2=read 	
	 mov   al, 01h
         int   13h                     ; BIOS Service func ( ah ) = 2
                                       ; Read disk sectors
				       ; BIOS Service func ( ah ) = 3
                                       ; Write disk sectors
                                       ;AL-sec num CH-cyl CL-sec
             	                       ; DH-head DL-drive ES:BX-buffer
             	                       ;CF-flag AH-stat AL-sec read
         pop   cx
         jnc   short dsk_rd_2
         loop  dsk_rd_1
dsk_rd_2:
	 mov word ptr [buff_s], si 
dsk_rd_3:
         retn

dsk_rd 	endp


m_get 	proc near
	; 01/03/2013
	; 18/11/2012
	; 14/11/2012 unix boot file configuration version
	; of "mget" procedure
	; 31/10/2012
	; 20/10/2012
	; 19/8/2012
	; 13/8/2012
	; 27/7/2012
     	; 21/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; return -> AX=R1
	; RETRO UNIX v1 FS
	; initialization/format version
	; cf -> 1 = error (no free block)

	;push bx
	;push cx
	;push dx
	 ;; contents of bx, cx, dx will be destroyed 
mget_0:
	mov bl, byte ptr [u_off]+1
        xor bh, bh
	; BX = R2
        test word ptr [inode_flgs], 4096 ; 1000h
			  	     ; is this a large or small file
	jnz short mget_5 ; 4f ; large file

        test bl, 0F0h ; !0Fh  ; error if BX (R2) >= 16                    
	jnz short mget_2

	and bl, 0Eh  ; clear all bits but bits 1,2,3
	mov ax, word ptr inode_dskp[BX] ; AX = R1, physical block number
	or ax, ax
	jnz short mget_1 ; if physical block number is zero
			 ; then need a new block for file
	call sb_alloc	 ; allocate a new block for this file	
			 ; AX (R1) = Block number
	jc short mget_8  ; ; cf -> 1 & ax = 0 -> no free block

	mov word ptr inode_dskp[BX], ax

	call set_imod
	
	call b_clear
	
mget_1: ; 2
	; AX (R1) = Physical block number

	;pop dx
	;pop cx
	;pop bx

	retn 

mget_2: ; 3
	; adding on block which changes small file to large file
	call sb_alloc 
	; call wslot  ; setup I/O buffer for write
	;	   ; R5 points to the first data word in buffer

	; push ds
	; pop es

	mov word ptr [buff_s], ax  ; Block/Sector number

	;push si
	;push di
	push ax

	mov cx, 8  ; R3, transfer old physical block pointers
		   ; into new indirect block area for the new
		   ; large file		
	mov di, offset WriteBuffer ; BX = R5
	mov si, offset inode_dskp 

	xor ax, ax ; mov ax, 0
mget_3: ; 1
	movsw
	mov word ptr [SI]-2, ax
	loop mget_3
	
	mov cl, 256-8 ; clear rest of data buffer

mget_4:	; 1
	rep stosw

	pop ax
	;pop di
	;pop si

	;mov byte ptr [buff_m], 1 ; modified
	call dsk_wr	
	;jc short mget_1
	jc short mget_8 ; 01/03/2013

	mov ax, word ptr [buff_s]

	mov word ptr [inode_dskp], ax
	or word ptr [inode_flgs], 4096 ; 1000h
	
	call set_imod

	jmp short mget_0

mget_9:
	pop ax
mget_8: 
	;mov ax, err_NOFREEBLOCK

	;pop dx
	;pop cx
	;pop bx

	retn

mget_5:  ; 4 ; large file
	; 05/03/2013
	;mov ax, bx   ; bx <= 255 for this file (UNIX v1, RUFS) system
	;mov cx, 256 ; 01/03/2013 no need a division here
	;xor dx, dx  ; 01/03/2013 no need a division here
	;div cx	     ; 01/03/2013 no need a division here
	;and bx, 1FEh  ; zero all bit but 1,2,3,4,5,6,7,8
		      ;	gives offset in indirect block
	;push bx			 ; R2	
	;mov bx, ax  ; calculate offset in i-node for pointer
		    ; to proper indirect block
	;and bx, 0Eh
	;mov ax, word ptr inode_dskp[BX] ; R1

	and bl, 0FEh ; ah = 0 ; 01/03/2013
	push bx	     ; i-node pointer offset in indirect block	
	; 01/03/2013 Max. possible BX (offset) value is 127 (65535/512)
	; 	     for this file system (offset 128 to 255 not in use)

	; There is always 1 indirect block for this file system
	mov ax, word ptr [inode_dskp] ; inode_dskp[0]

	or ax, ax ; R1
	jnz short mget_6 ; 2f
	
	call sb_alloc
	jc short mget_9 ; 01/03/2013

	mov word ptr inode_dskp[BX], ax  ; R1, block number

	call set_imod

	call b_clear		

mget_6: ;2
	; ax = R1, block number
	call dsk_rd ; read indirect block
	pop bx  ; R2, get offset
	jc short mget_7
	add bx, offset WriteBuffer ; R5, first word of indirect block
	mov ax, word ptr [bx] ; put physical block no of block
			      ; in file sought in R1 (AX)
	or ax, ax
        jnz short mget_7 ; 2f 

	call sb_alloc
	jc short mget_8 ; 01/03/2013

	mov word ptr [bx], ax ; R1
	
	push ax
	mov ax, word ptr [buff_s]

	;mov byte ptr [buff_m], 1 ; modified

	;call wslot
	call dsk_wr
	pop dx ; 18/11/2012
	jc short mget_7 

	mov ax, dx ; 18/11/2012
	; ax = R1, block number of new block

	call b_clear	

mget_7: ; 2
	; ax = R1, block number of new block
	;pop dx
	;pop cx
	;pop bx 
	
	retn

m_get endp


sb_alloc proc near
	; 14/11/2012 unix boot file configuration version
	; of "alloc" procedure
	; 21/8/2012
	; 18/8/2012
	; 17/8/2012
	; 5/8/2012		
 	; 21/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; input -> AX=R1 
	;; output -> AX=R1
	; RETRO UNIX v1 FS

	;push cx
	push bx ; R2
	;push dx ; R3

	mov bx, offset systm ; SuperBlock 
		; start of inode and free storage map for disk
alloc_1: ; 1
	mov ax, word ptr [BX] ; first word contains # of bytes 
	                ; in free storage map
	shl ax, 1	; multiply AX (R1) by 8 gives # of blocks
	shl ax, 1
	shl ax, 1
	mov cx, ax ; R1, bit count of free storage map
	xor ax, ax ; 0
alloc_2: ; 1
	inc bx ; 18/8/2012
	inc bx ; 
	mov dx, word ptr [BX]  ; mov (R2)+, R3
	or dx, dx
	jnz short alloc_3 ; 1f
			; branch if any free blocks in this word	
	add ax, 16
	cmp ax, cx    
	jb short alloc_2 ; 1b

	;jmp short panic  ; no free storage 

	xor ax, ax
	stc		 ; cf=1 --> error: no free block

	jmp short alloc_7	

alloc_3: ; 1
        shr dx, 1  ; R3  ; Branch when free block found,
			 ; bit for block k is in byte k/8 
			 ; in bit k (mod 8) 	
	jc short alloc_4 ; 1f
	inc ax  ; R1     ; increment bit count in bit k (mod 8)    
	jmp short alloc_3 ; 1b
	
alloc_4:
	;call free_3
sb_alloc_free_3:	
	mov dx, 1	
	mov cx, ax
	and cx, 0Fh
	jz short @f
	shl dx, cl
@@:
	mov bx, ax
	shr bx, 1
	shr bx, 1
	shr bx, 1
	shr bx, 1
free_4: ; 1
	shl bx, 1 ; 21/8/2012
         ; BX (R2) = k/8	
	add bx, offset systm+2 ; SuperBlock+2

alloc_5: ; 1 
	; 21/8/2012
	not dx ; masking bit is '0' and others are '1'
	and word ptr [BX], dx    ; bic r3, (r2) 	
	; 0 -> allocated	retn
alloc_6:
	; inc byte ptr [smod] ; super block modified sign
	;mov byte ptr [smod], 1
alloc_7:
	;pop dx ; R3
	pop bx ; R2
	;pop cx 
	; AX (R1) = Block number
	retn

sb_alloc endp


set_imod proc near
	; 14/11/2012 unix boot file configuration version
	; of "setimod" procedure
	; 13/8/2012
	; 21/7/2012
	; 14/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; AX=R0, BX=R1, CX=R3, DX=R5 
	; [SP] = Argument 1, 0 = read, 1 = write
	; RETRO UNIX v1 FS
	; initialization/format version
	;

	;push dx
	push ax

	mov byte ptr [imod], 1

	; Erdogan Tan 14-7-2012
	call epoch
	
	mov word ptr [inode_mtim], ax
	mov word ptr [inode_mtim]+2, dx

	cmp word ptr [inode_ctim], 0
	ja short @f
	cmp word ptr [inode_ctim]+2, 0
	ja short @f

	mov word ptr [inode_ctim], ax
	mov word ptr [inode_ctim]+2, dx
@@:
	pop ax
        ;pop dx

	retn

set_imod endp


b_clear	proc near
	; 18/11/2012
	; 14/11/2012 unix boot file configuration version
	; of "clear" procedure
	; 5/8/2012
 	; 21/7/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;; input -> AX=R1 (block number)
	;; output -> AX=R1
	; RETRO UNIX v1 FS
	; initialization/format version

	;call wslot ; setup I/O buffer for write
	;	   ; R5 points to the first data word in buffer
	; BX = R5


	mov word ptr [buff_s], ax 
	
	;push ds
	;pop es
	
	;push di
	;push cx
	push ax
 	xor ax, ax
	; mov di, bx
	mov di, offset WriteBuffer
	mov cx, 256 
	rep stosw
	
	;mov byte ptr [buff_m], 1 ; modified

	mov ax, word ptr [buff_s] ; 18/11/2012

	call dsk_wr

	pop ax
	;pop cx
	;pop di	
	
	retn

b_clear  endp


mak_nod proc near
	; 01/03/2013
	; 02/12/2012 (maknod_imap -> call imap)
	; 25/11/2012
	; 18/11/2012
	; 11/11/2012
	; unixboot.asm (boot file configuration)
	; version of 'maknod'
	;
	; 30/10/2012
	; AX = R1, mode
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	; RETRO UNIX v1 FS
	;
	; maknod : create an i-node and make a directory entry
	;
	; 8086 CPU & IBM PC architecture modifications by Erdogan Tan 
	;
	; return => if cf=1 error code in AH
	; If cf=0 -> AX = I-Number (also in u.dirbuff)

	or 	ah, 80h  ; 10000000b, allocate flag set
	push 	ax 	 ; put mode on stack
	;mov	ax, word ptr [ii] ; move current i-number to BX/r1
	
	;mov ax, ROOT_DIR_INODE_NUMBER ; 41
	;call i_get
	;jc short short maknod_2

	;test word ptr [i.flags], 4000h ; directory i-node ?
	;jnz short maknod_1

	;mov ah, 0FFh ; error number
	;stc
	;jmp short maknod_2

	mov	ax, 41	 ; r1 = 41

maknod_1: ; 1 		 ; scan for a free i-node
	inc	ax 	 ; r1 = r1 + 1
	; 2/12/2012
	call	imap     ; get byte address and bit position in inode map in 
			 ; r2 (DX) & mq (BX)
            ; DX (MQ) has a 1 in the calculated bit position
            ; BX (R2) has byte address of the byte with allocation bit

        test    byte ptr [BX], dl ; bitb mq,(r2) / is the i-node active
	jnz	short maknod_1    ; bne	1b / yes, try the next one
        or      byte ptr [BX], dl ; bisb mq,(r2)
				  ; no, make it active (put a 1 in the bit map)
	; ax = i-number
	call	i_get      	  ; jsr	r0,iget / get i-node into core
	jc	short maknod_2	
	
	test	word ptr [inode_flgs], 8000h  ; is i-node already allocated
	jnz	short maknod_1    ; 1b / yes, look for another one
	
	mov	word ptr [u_dirbuf], ax ; mov r1, u.dirbuf 
				        ; no, put i-number in u.dirbuf

	mov	ax, ROOT_DIR_INODE_NUMBER ; 41
	call 	i_get		   ; jsr r0,iget / get i-node in core
	jc	short maknod_2

	call 	mk_dir 		   ; jsr r0,mkdir 
				   ; make a directory entry in current directory
	jc	short maknod_2 ; 01/03/2013   

	mov	ax, word ptr [u_dirbuf] ; mov u.dirbuf,r1 
				   ;  ax / r1 = new inode number
	call	i_get
	jc	short maknod_2

        ; jsr r0,copyz; inode; inode+32. / 0 it out 
	mov	cx, 16
	xor	ax, ax ; 0
	mov	di, offset inode 
	rep	stosw

	pop	word ptr [inode_flgs] ; mov (sp)+,i.flgs / fill flags
	mov 	al, byte ptr [u_uid] ; movb u.uid,i.uid / user id
	mov 	byte ptr [inode_uid], al
	mov     byte ptr [inode_nlks], 1 ; movb $1,i.nlks / 1 link
	
	;call	epoch

	;mov 	word ptr [s_time], ax
	;mov 	word ptr [s_time]+2, dx	

	;mov 	word ptr [inode_ctim], ax ; mov s.time,i.ctim / time created
	;mov 	word ptr [inode_ctim]+2, dx ; mov s.time+2,i.ctim+2

	; 25/11/2012

	mov 	ax, word ptr [bf_make_datetime]
	mov	dx, word ptr [bf_make_datetime]+2

	mov 	word ptr [inode_ctim], ax 
	mov 	word ptr [inode_ctim]+2, dx
	
	call	set_imod

	mov 	ax, word ptr [u_dirbuf]
	retn

maknod_2:
	pop	ax
	retn

mak_nod	endp


mk_dir proc near
	; 11/11/2012
	; unixboot.asm (boot file configuration)
	; version of 'mkdir'
	;
	; 31/10/2012
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	; RETRO UNIX v1 FS
	;
	; mkdir : make a directory entry
	;
	; 8086 CPU & IBM PC architecture modifications by Erdogan Tan 
	;
	; return => if cf=1 error number in [Error], ax = mode
	; If cf=0 -> AX = I-Number (also in u.dirbuff)
	;
	; input:
	; u.namep = file name
	; ii = current directory's i-number
	; u.dirbuf = directory entry (source) location
	; output:
	; u.dirbuf+2 to u.dirbuf+10 = file name
	; u.off = directory entry offset in current directory
	; u.base = start of u.dirbuf
	; ;;;r1 (AX) = i-number of current directory

mkdir_0:
	; jsr r0,copyz; u.dirbuf+2; u.dirbuf+10. / clear this
	mov 	cx, 4
	xor 	ax, ax
	mov 	di, offset u_dirbuf+2
	rep 	stosw	
         
        mov	si, word ptr [u_namep] ; mov u.namep,r2 
				     ; r2 points to name of directory entry

	mov	di, offset u_dirbuf+2 ; mov $u.dirbuf+2,r3
				      ; r3 points to u.dirbuf+2
mkdir_1: ;1 / put characters in the directory name in u.dirbuf+2 - u.dirbuf+10
	lodsb 			;movb  (r2)+,r1 / move character in name to r1
	and 	al, al
	jz 	short mkdir_2 	      ; beq 1f / if null, done
	cmp 	al, '/'  	      ; cmp r1,$'/ / is it a "/"?
	je	short mkdir_stc       ; beq	error9 / yes, error
	cmp	di, offset u_dirbuf+10 ; 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_2: ;1
	mov 	ax, word ptr [u_dirp] ; mov u.dirp,u.off
	mov 	word ptr [u_off], ax  ; pointer to empty current directory
				      ; slot to u.off
wdir:
	mov	word ptr [u_base], offset u_dirbuf
	                              ; mov$u.dirbuf,u.base
				      ; u.base points to created file name
	mov	word ptr [u_count], 10 ; mov $10.,u.count
 				       ; u.count = 10
	mov	ax, word ptr [ii]    ; mov ii,r1 
				     ; r1 has i-number of current directory

	call	write_i		     ; jsr r0,writei / write into directory
@@:	
	retn			     ; rts r0

mkdir_stc:
	; invalid file name, al="/", ah=0
	mov ah, 1
	stc
	retn

mk_dir 	endp


write_i proc near
	; 18/11/2012
	; 11/11/2012
	; unixboot.asm (boot file configuration)
	; version of 'writei'
	;
	; 31/10/2012
	; 18/08/2012
	; 17/07/2012
	; BX = R1, i-number
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	;
	; RETRO UNIX v1 FS
	; initialization/format version
	;
	; writei: write file
	;
	; 8086 CPU & IBM PC architecture modifications by Erdogan Tan 
	;; return => if cf=1 error number in [Error]

	; input:
	; AX = R1 = I-Number
	; u.count = byte count
	; u.base = user buffer (offset)
	; u.fofp = (pointer to) current file offset
 
	xor dx, dx ; 0		   ; clr u.nread	
	mov word ptr [u_nread], dx ; clear the number of bytes transmitted during
				   ; read or write calls 
				   ; tst u.count		
	cmp word ptr [u_count], dx ; test the byte count specified by the user
	;ja short write_1 ; 1f	   ; bgt 1f / any bytes to output; yes, branch
	;retn			   ; rts 0 / no, return - no writing to do
	jna short write_inode_retn

write_1:
	;push ax		; save i-number on stack

	call i_get 	; jsr	r0,iget
		  	; write i-node out (if modified), read i-node 'r1'
		        ; into i-node area of core
	mov dx, word ptr [u_off] 
	add dx, word ptr [u_count]
			; add u.count,r2 
			; no. of bytes to be written + file offset is
		        ; put in r2

	cmp dx, word ptr [inode_size] ; cmp r2,i.size
		         ; is this greater than the present size of
		         ; the file?
	jna short dskw_1 ; blos	 1f / no, branch

	mov word ptr [inode_size], dx ; mov	r2,i.size 
			 ; yes, increase the file size to file offset +
		         ; no. of data bytes
	call set_imod    ; jsr r0,setimod 
			 ; set imod=1 (i.e., core inode has been
		         ; modified), stuff time of modification into
		         ; core image of i-node
dskw_1: ; 1 		
	call m_get 	; jsr r0,mget 
			; get the block no. in which to write the next data
  		        ; byte
			; AX = R1 = Block Number

	mov bx, word ptr [u_off]
	and bx, 1FFh  		 ; bit	*u.fofp,$777
				 ; test the lower 9 bits of the file offset
	jnz short dskw_2 ; bne 2f 
			; if its non-zero, branch; if zero, file offset = 0,
		   	; 512, 1024,...(i.e., start of new block)
	cmp word ptr [u_count], 512 ; cmp u.count,$512.
			        ; if zero, is there enough data to fill an
		              	; entire block? (i.e., no. of
	;jnb short dskw_3 ; bhis 3f / bytes to be written greater than 512.? 
			; Yes, branch. / Don't have to read block
; 18/11/2012
	jb short dskw_2

	mov word ptr [buff_s], ax 

	jmp short short dskw_3	

dskw_2: ; 2
	; in as no past info. is to be saved (the entire block will be
        ; overwritten).
			; AX=R1 (block number)
	call dsk_rd 	; jsr r0,dskrd 
			; no, must retain old info.. Hence, read block 'r1'
		        ; into an I/O buffer
; 11/11/2012
	jc short dskw_5
	mov ax,word ptr [buff_s]

dskw_3: ; 3
	;call wslot

writeinode_sioreg:
	; call sioreg

        mov di, word ptr [u_off] ; R2
	mov cx, di ; cx = R3, di = R2
	or cx, 0FE00h ; set bits 9...15 of file offset in R3
	and di, 1FFh ; calculate file offset mod 512
	add di, offset WriteBuffer ; di now points to 1st byte in buffer
		   ; where data is to be placed
        mov si, word ptr [u_base] ; R1
	neg cx ; 512 - file offset(mod512) in R3 (cx)
        cmp cx, word ptr [u_count]
	jna short @f ; 2f

        mov cx, word ptr [u_count]
@@:
	add word ptr [u_nread], cx ; r3 + number of bytes
			; xmitted during write is put into
                        ; u_nread
        sub word ptr [u_count], cx
        add word ptr [u_base], cx ; points to 1st of remaining
			; data bytes
        add word ptr [u_off], cx ; new file offset = number 
			; of bytes done + old file offset
; end of writeinode_sioreg

	; SI = user data offset (r1)
	; DI = sector (I/O) buffer offset (r2)
	; CX = byte count (r3)

dskw_4: ; 2
	rep movsb

	; ax = block/sector number

	call dsk_wr ; jsr r0,dskwr / write the block and the i-node
        jc short dskw_5

        cmp word ptr [u_count], 0 ; any more data to write?
	ja short dskw_1 ; 1b   ; yes, branch

dskw_5:
	; pop ax ; i-number

write_inode_retn:
	retn

write_i	endp


dsk_wr	proc near
	; 11/11/2012
	; unix boot file configuration version of "dskwr" procedure
	;
     	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972
	; RETRO UNIX v1 FS
	;; return => if cf=1 error number in [Error]

	 ; ax = sector/block number

	 mov bx, offset WriteBuffer

	 xor ch, ch
	 mov cl, 4 ; Retry count
dsk_wr_1:
         push  cx
         mov   dx, 18                  ; Sectors per track
         div   dl                      
         mov   cl, ah                  ; Sector (zero based)
         inc   cl                      ; To make it 1 based
         shr   al, 1		       ; Convert Track to Cylinder
         adc   dh, 0                   ; Heads (0 or 1)

         mov   dl, byte ptr [PhysicalDriveNumber] 
         mov   ch, al

	 mov   ah, 3 		       ; 3=write 	
	 mov   al, 01h
         int   13h                     ; BIOS Service func ( ah ) = 2
                                       ; Read disk sectors
				       ; BIOS Service func ( ah ) = 3
                                       ; Write disk sectors
                                       ;AL-sec num CH-cyl CL-sec
             	                       ; DH-head DL-drive ES:BX-buffer
             	                       ;CF-flag AH-stat AL-sec read
         pop   cx
         jnc   short dsk_wr_2
         loop  dsk_wr_1
dsk_wr_2:
         retn

dsk_wr 	endp


epoch proc near
	; 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

	; 21/7/2012
	;push bx
	;push cx

	mov ah, 02h                      ; Return Current Time
        int 1Ah
        xchg ch,cl
        mov word ptr [hour], cx
        xchg dh,dl
        mov word ptr [second], dx

        mov ah, 04h                      ; Return Current Date
        int 1Ah
        xchg ch,cl
        mov word ptr [year], cx
        xchg dh,dl
        mov word ptr [month], dx

	mov cx, 3030h

	
	mov al, byte ptr [hour] ; Hour
           ; AL <= BCD number)
        db 0D4h,10h                     ; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad ; AX= AH*10+AL
		
	mov byte ptr [hour], al

	mov al, byte ptr [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 byte ptr [minute], al

	mov al, byte ptr [second] ; Second
           ; AL <= BCD number)
        db 0D4h,10h                     ; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad ; AX= AH*10+AL
		
	mov byte ptr [second], al

	
	mov ax, word ptr [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 word ptr [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 word ptr [year], ax


	mov al, byte ptr [month] ; Month
           ; AL <= BCD number)
        db 0D4h,10h                     ; Undocumented inst. AAM
					; AH = AL / 10h
					; AL = AL MOD 10h
        aad ; AX= AH*10+AL
	
	mov byte ptr [month], al	


	mov al, byte ptr [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 byte ptr [Day], al
	
convert_to_epoch:
	; Derived from DALLAS Semiconductor
	; Application Note 31 (DS1602/DS1603)
	; 6 May 1998

	mov dx, word ptr [year]
	sub dx, 1970
	mov ax, 365
	mul dx
	xor bh, bh
	mov bl, byte ptr [month]
	dec bl
	shl bl, 1
	mov cx, word ptr DMonth[BX]
	mov bl, byte ptr [Day]
	dec bl
	
	add ax, cx
	adc dx, 0
	add ax, bx
	adc dx, 0
				; DX:AX = days since 1/1/1970
	mov cx, word ptr [year]
	sub cx, 1969
	shr cx, 1
	shr cx, 1		
		; (year-1969)/4
	add ax, cx
	adc dx, 0
				; + leap days since 1/1/1970

	cmp byte ptr [month], 2  ; if past february
	jna short @f
	mov cx, word ptr [year]
	and cx, 3 ; year mod 4
	jnz short @f		
				; and if leap year
	add ax, 1 ; add this year's leap day (february 29)
	adc dx, 0
@@: 			; compute seconds since 1/1/1970
	mov bx, 24
	call proc_mul32

	mov bl, byte ptr [hour]
	add ax, bx
	adc dx, 0
	
	mov bx, 60
	call proc_mul32

	mov bl, byte ptr [minute]
	add ax, bx
	adc dx, 0
	
	mov bx, 60
	call proc_mul32

	mov bl, byte ptr [second]
	add ax, bx
 	adc dx, 0

	; DX:AX -> seconds since 1/1/1970 00:00:00

	; 21/7/2012
	;pop cx
	;pop bx
	
	retn

epoch endp

convert_from_epoch proc near
	; 30/11/2012
	; Derived from DALLAS Semiconductor
	; Application Note 31 (DS1602/DS1603)
	; 6 May 1998
	;
	; INPUT:
	; DX:AX = Unix (Epoch) Time
	mov cx, 60
	call proc_div32
	;mov word ptr [imin], ax   ; whole minutes
	;mov word ptr [imin]+2, dx ; since 1/1/1970
	mov word ptr [second], bx  ; leftover seconds
	; mov cx, 60
	call proc_div32
	;mov word ptr [ihrs], ax   ; whole hours
	;mov word ptr [ihrs]+2, dx ; since 1/1/1970
	mov word ptr [minute], bx  ; leftover minutes
	; mov cx, 24
	mov cl, 24
	call proc_div32
	;mov word ptr [iday], ax  ; whole hours
				  ; since 1/1/1970
	; mov word ptr [iday]+2, dx ; DX = 0
	mov word ptr [hour], bx   ; leftover hours
	add ax, 365+366		  ; whole day since
				  ; 1/1/1968 	
	; adc dx, 0	          ;  DX = 0
	; mov word ptr [iday], ax
	push ax
	mov cx, (4*365)+1	  ; 4 years = 1461 days
	call proc_div32
	pop cx
	;mov word ptr [lday], ax  ; count of quadyrs (4 years)
	push bx
	;mov word ptr [qday], bx  ;  days since quadyr began
	cmp bx, 31 + 29           ; if past feb 29 then
	cmc			  ; add this quadyr's leap day
	adc ax, 0		  ; to # of qadyrs (leap days)
	;mov word ptr [lday], ax  ; since 1968			  
	;mov cx, word ptr [iday]
	xchg cx, ax		  ; CX = lday, AX = iday		  
	sub ax, cx		  ; iday - lday
	mov cx, 365
	;xor dx, dx		  ; DX  = 0
	; AX = iday-lday, DX = 0
	call proc_div32
	;mov word ptr [iyrs], ax   ; whole years since 1968
	; jday = iday - (iyrs*365) - lday
	;mov word ptr [jday], bx  ; days since 1/1 of current year
	add ax, 1968		  ; compute year
	mov word ptr [year], ax
	mov dx, ax		
	;mov ax, word ptr [qday]
	pop ax
	cmp ax, 365		  ; if qday <= 365 and qday >= 60	
	ja short @f		  ; jday = jday +1
	cmp ax, 60	          ; if past 2/29 and leap year then
        cmc			  ; add a leap day to the # of whole
	adc bx, 0		  ; days since 1/1 of current year
@@:			
	;mov word ptr [jday], bx
	mov cx, 12		  ; estimate month
	xchg cx, bx		  ; CX = jday, BX = month 	
	mov ax, 366		  ; mday, max. days since 1/1 is 365
	and dx, 11b		  ; year mod 4	(and dx, 3) 
@@:	; Month calculation	  ; 0 to 11  (11 to 0)	
	cmp cx, ax		  ; mday = # of days passed from 1/1
	jnb short @f
	dec bx			  ; month = month - 1
	shl bx, 1 
	mov ax, word ptr DMonth[BX] ; # 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 @b		  ; then mday = mday + 1
	or dl, dl		  ; if past 2/29 and leap year then
	jnz short @b		  ; add leap day (to mday)
	inc ax			  ; mday = mday + 1
	jmp short @b
@@:
	inc bx 			  ; -> bx = month, 1 to 12
	mov word ptr [month], bx
	sub cx, ax		  ; day = jday - mday + 1	
	inc cx 			  
	mov word ptr [day], cx
	
	; ax, bx, cx, dx is changed at return
	; output ->
	; [year], [month], [day], [hour], [minute], [second]
	; 

	retn

convert_from_epoch endp


proc_mul32 proc near

    ; push cx

      mov cx, bx
      mov bx, dx

      mul cx

      xchg ax, bx

      push dx

      mul cx 

      pop cx 

      add ax, cx 
      adc dx, 0

      xchg bx, ax
      xchg dx, bx

    ; pop cx

      retn

proc_mul32 endp


proc_div32 proc near
	; 1999
	; (Rx_Dos_Div32) 32 bit divide procedure 
	; by Erdogan Tan
	; Input -> DX_AX = 32 bit dividend
	;          CX = 16 bit divisor
	; output -> DX_AX = 32 bit quotient
	;          BX = 16 bit remainder
	mov  bx, dx
	xchg ax, bx
	xor  dx, dx
	div  cx         ; at first, divide DX
	xchg ax, bx     ; remainder is in DX
			; now, BX has quotient
			; save remainder
	div  cx         ; so, DX_AX divided and
			; AX has quotient
			; DX has remainder
	xchg dx, bx     ; finally, BX has remainder

	retn

proc_div32 endp


sync 	proc near
	; 18/11/2012 unix boot file configuration version
	; of "sync" procedure of retro unix v1.0 by Erdogan Tan
	; 12/8/2012
	; updates super block and the last i-node on disk 
	; if modified
	; e.g. smod = 1, imod = 1, buffer_m = 1
	;
	; RETRO UNIX v1 FS

	xor ax, ax ; mov ax, 0
        call i_get ; (write modified i-node)
	jc short sync_2
sync_1:
        mov bx, offset BSBuffer
        mov ax,0302h  ; Write boot sector & super block
        mov cx,1
        xor dh,dh
	;mov dl, byte ptr [PhysicalDriveNumber]
        int 13h
sync_2:
        retn	

sync	endp


find_bfn proc near
	; 26/11/2012
	; 25/11/2012
	;
	; find boot file name by i-number (ax)
	;
	; cf -> 1 means error, ax = 0 -> not found

	mov word ptr [bf_i_number], ax
	push si

	mov ax, ROOT_DIR_INODE_NUMBER ; 41
	call i_get
	jc short loc_find_bfn_retn

	;test word ptr [inode_flgs], 4000h ; directory i-node ?
	;jnz short @f

	;mov ah, 0FFh ; error number
	;stc
	;jmp short loc_find_bfn_retn
;;@@:
	xor ax, ax 
	mov word ptr [u_off], ax ; u_off is file offset used by user

loc_find_bfn_1:
	mov word ptr [u_base], offset u_dirbuf
				  ; u.dirbuff holds a file name copied from
				  ; a directory	
	mov word ptr [u_count], 10 	
 	
	mov ax, ROOT_DIR_INODE_NUMBER 

	call read_i ; read 10 bytes of file with i-number
		   ; i.e. read a directory entry
	jc short loc_find_bfn_retn

	mov ax, word ptr [u_nread]

	or ax, ax
	jz short loc_find_bfn_2 ; gives error return 

	mov ax, word ptr [u_dirbuf]

	cmp ax, word ptr [bf_i_number] ; Check i-number of directory entry
	jne short loc_find_bfn_1       ; if same with specified bf_i_number
				       ; it is the boot file 
loc_find_bfn_3:
	call i_get
loc_find_bfn_retn:
	pop si
	retn

loc_find_bfn_2:
	stc
	jmp short loc_find_bfn_retn
	
find_bfn endp


proc_display_startupfile_info proc near
	       ; 30/11/2012	
	       ; 29/11/2012 ; @@
               ; 25/11/2012
              
 		mov si, offset Msg_StartupFile_Name
                call UNIX_PRINTMSG

		mov si, offset Boot_File_Name
                call UNIX_PRINTMSG

                mov si, offset Str_Inode_Number
                call UNIX_PRINTMSG

		mov si, offset BSBuffer
		mov ax, word ptr [SI]+bs_BF_inode_Number

		mov si, offset Decimal_i_no_str
		mov cx, 5
		call proc_bin_to_decimal

		mov si, offset Decimal_i_no_str 

		mov cx, 4
@@:
		cmp byte ptr [SI], '0'
                ja short @f
		inc si
                loop @b 
@@:
                call UNIX_PRINTMSG

                mov si, offset Str_startup_file_size
                call UNIX_PRINTMSG

		mov ax, word ptr [Inode_size]
		mov si, offset Decimal_size_str
		;mov cx, 5
		mov cl, 5
		call proc_bin_to_decimal

		mov si, offset Decimal_size_str

		mov cl, 4
@@:
		cmp byte ptr [SI], '0'
                ja short @f
		inc si
                loop @b 
@@:
                call UNIX_PRINTMSG

		mov si, offset Str_Bytes
                call UNIX_PRINTMSG

		; 30/11/2012
	
		mov si, 3030h		

		mov ax, word ptr [Inode_ctim]
		mov dx, word ptr [Inode_ctim]+2

		call convert_from_epoch
		
		mov ax, word ptr [year]
		mov si, offset str_cyear
		;mov cx, 4
		mov cl, 4
		call proc_bin_to_decimal
		
		mov ax, word ptr [month]
		mov si, offset str_cmonth
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [day]
		mov si, offset str_cday
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [hour]
		mov si, offset str_chour
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [minute]
		mov si, offset str_cminute
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [second]
		mov si, offset str_csecond
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [Inode_mtim]
		mov dx, word ptr [Inode_mtim]+2

		call convert_from_epoch
		
		mov ax, word ptr [year]
		mov si, offset str_myear
		;mov cx, 4
		mov cl, 4
		call proc_bin_to_decimal
		
		mov ax, word ptr [month]
		mov si, offset str_mmonth
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [day]
		mov si, offset str_mday
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [hour]
		mov si, offset str_mhour
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [minute]
		mov si, offset str_mminute
		mov cl, 2
		call proc_bin_to_decimal

		mov ax, word ptr [second]
		mov si, offset str_msecond
		mov cl, 2
		call proc_bin_to_decimal

		mov si, offset Str_SF_date_Time
                call UNIX_PRINTMSG
                
		retn  

proc_display_startupfile_info endp


proc_bin_to_decimal proc near
	       ; 30/11/2012 (CX input)	
	       ; 25/11/2012 unixboot.asm version	
               ; 6-5-2009
               ;  Erdogan Tan
               ; INPUT: DS:SI = Target location
               ;        AX = Binary Number
	       ;        CX = Number of digits	
               ; OUTPUT: Decimal chars at DS:SI
               ; CX, AX, DX will be changed.

                ;push bp
		;push si
loc_reset_str_NumberInput:
                mov byte ptr [SI], "0"
                inc si
                loop loc_reset_str_NumberInput
                mov bp, sp
                xor dx, dx
		mov cx, 10
loc_rediv_NumberInput:
                div cx
		add dl,'0'
                push dx
                xor dx, dx
		dec si
		or ax, ax
		jnz short loc_rediv_NumberInput
loop_popcx_NumberInput: 
                pop dx
                mov byte ptr [SI], dl
                inc si
                cmp bp, sp
                jne short loop_popcx_NumberInput
                ;pop si
                ;pop bp  
 
                retn

proc_bin_to_decimal endp


unlink proc near
        ; 02/12/2012
        ; unix boot file configuration version
	; of "sysunlink" function of retro unix v1.0 by Erdogan Tan
	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972 
	; ('sysunlink', unix kernel function)
	; 
	; INPUT -> AX (R1) = inode number
	;          [u_off] = Directory Entry Offset + 10
	;          [ii] = i-number of current directory
	; Return -> CF = 0 -> Successed, CF = 1 -> failed
	;                               (error code in AX)

		;jsr r0,arg; u.namep / u.namep points to name
		;jsr r0,namei / find the i-number associated 
		;                with the path name
		;br error9 / not found
	
	push ax ;mov r1,-(sp) / put its i-number on the stack
		;jsr r0,isdir / is it a directory
	xor ax, ax
	mov word ptr [u_dirbuf], ax ; clr u.dirbuf / no, clear 
			 ;the location that will get written
	                 ;/ into the i-number portion of the entry
	sub word ptr [u_off], 10 ; sub $10.,u.off 
				 ; / move u.off back 1 directory entry
	; not as unix original code
	; because 'find_bfn' procedure loads boot file inode at return
	; so, it is neded to reload root directory inode in core/memory
	mov ax, ROOT_DIR_INODE_NUMBER 
	call i_get
	jnc short @f
	pop ax
	retn
	;
@@:
	call wdir ;jsr r0,wdir / free the directory entry
	pop ax  ;mov (sp)+,r1 / get i-number back
	jc short @f
        call i_get ; jsr r0,iget / get i-node
	jc short @f
        call set_imod ; jsr r0,setimod / set modified flag
        dec byte ptr [inode_nlks] ; decb i.nlks 
				  ; / decrement the number of links
	jnz short @f ;bgt sysret9 
		     ;/ if this was not the last link to file return
	call anyi    ;jsr r0,anyi / if it was, see if anyone has it open.
		     ;Then / free contents of file and destroy it.
		     ;br sysret9
@@:
	retn


unlink endp


anyi proc near
        ; 02/12/2012
        ; unix boot file configuration version
	; of "anyi" procedure of retro unix v1.0 by Erdogan Tan
	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972 
	; ('anyi' procedure)
	; 
	; INPUT -> AX (R1) = inode number
	; Return -> CF = 0 -> Successed, CF = 1 -> failed
	;                               
	    ; mov $fsp,r2 / move start of fsp table to r2
anyi_1: ;1
	    ; cmp r1,(r2) / do i-numbers match?
	    ; beq 1f / yes, 1f
	    ; neg r1 / no complement r1
	    ; cmp r1,(r2) / do they match now?
	    ; beq 1f / yes, transfer
		   ; / i-numbers do not match
	    ; add $8,r2 / no, bump to next entry in fsp table
	    ; cmp r2,$fsp+[nfiles*8] / are we at last entry in the table
	    ; blt 1b / no, check next entries i-number
	    ; tst r1 / yes, no match
	    ; bge .+4
	    ; neg	r1 / make i-number positive
	call imap ; jsr	r0,imap / get address of allocation bit 
		  ;          	in the i-map in r2
        ; DX (MQ) has a 1 in the calculated bit position
        ; BX (R2) has byte address of the byte with allocation bit
	push bx ; retro unix modification (not as original unix code)
	push dx ; retro unix modification (not as original unix code)
	; AX = i-number
	call itrunc ; jsr r0,itrunc / free all blocks related to i-node
	
	pop dx ; retro unix modification (not as original unix code)
	pop bx ; retro unix modification (not as original unix code)

	jc short @f

        ; (AX=0)
	; retro unix modification-> 'call itrunc' moved up for
	; keeping super block unmodified if itrunc return with an error

        not dx
        and byte ptr [BX], dl ; bicb mq,(r2) 
			      ; / clear bit for i-node in the imap
	; xor ax, ax
	mov word ptr [inode_flgs], ax ; 0 ; clr	i.flgs
				   ; / clear all flags in the i-node
@@:
	retn ; rts r0 / return

;anyi_2: ;1 / i-numbers match
        ; incb	7(r2) / increment upper byte of the 4th word
	; rts r0 / in that fsp entry (deleted flag of fsp entry)

anyi endp


imap proc near
        ; 02/12/2012
        ; unix boot file configuration version
	; of "imap" procedure of retro unix v1.0 by Erdogan Tan
	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972 
	; ('imap' procedure)

	; 11/11/2012 (maknod_imap location -> imap procedure)
        mov bx, ax   ; BX = R2, AX = R1 (input, i-number)
        sub bx, 41   ; BX has i-41
        mov cl, bl   ; CX = R3   
        mov dx, 1    ; 
	and cl, 7    ; CX has (i-41) mod 8 to get the bit position 	 	
	jz short @f  ; 21/8/2012
        shl dx, cl   ; DX has 1 in the calculated bit position
@@:
        shr bx, 1
        shr bx, 1
        shr bx, 1    ; BX has (i-41) base 8 of byte number
		     ; from the start of the (inode) map		

        add bx, word ptr [systm] ; superblock free map size + 4
        add bx, offset systm+4 ; is inode map offset in superblock 

        ; DX (MQ) has a 1 in the calculated bit position
        ; BX (R2) has byte address of the byte with allocation bit

	retn

imap	endp


itrunc proc near
        ; 01/12/2012
        ; unix boot file configuration version
	; of "itrunc" procedure of retro unix v1.0 by Erdogan Tan
	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972 
	; ('itrunch' procedure)
	; 
	; INPUT -> AX (R1) = inode number
	; Return -> CF = 0 -> Successed, CF = 1 -> failed
	;                               (error code in AX)

	call 	i_get ; jsr r0,iget
	jc	short  @f
	mov 	si, offset inode_dskp ; mov $i.dskp,r2
	mov	di, si
itrunc_1:
	lodsb 	; mov (r2)+,r1 / move physical block number into r1
	or	ax,ax
	jz	short itrunc_5 ; beq 5f
	push	si ;  mov r2,-(sp)
        test    word ptr [inode_flgs], 1000h    
		; bit $10000,i.flgs / test large file bit?
	jz	short itrunc_4   ; beq 4f / if clear, branch
	push	ax ; mov r1,-(sp) / save block number of indirect block
	call	dsk_rd ; jsr r0,dskrd / read in block,
	; bx = Buffer offset          ; 1st data word pointed to by r5
	jc	short @f
	mov	cx, 256 ; mov $256.,r3 / move word count into r3
itrunc_2:
	mov	ax, word ptr [BX] ; mov	(r5)+,r1
		 ; / put 1st data word in r1; physical block number
	inc	bx
	and	ax, ax
	jz	itrunc_3 ; beq	3f / branch if zero
	push	cx  ; mov r3,-(sp) / save r3, r5 on stack
	push	bx  ; mov r5,-(sp)
	call	free  ; jsr r0,free / free block in free storage map
	pop	bx  ; mov (sp)+,r5
	pop	cx ;  mov (sp)+,r3
itrunc_3:
	loop	itrunc_2  ; dec r3 / decrement word count
			  ; bgt	2b / branch if positive
	pop	ax ; mov (sp)+,r1 
		   ; / put physical block number of indirect block
itrunc_4:
	call	free  ; jsr r0,free / free indirect block
	pop	si    ; mov (sp)+,r2
itrunc_5:
	cmp	si, offset inode_dskp + 16 ; cmp r2,$i.dskp+16.
	jb	short itrunc_1 ; bne 1b 
			; / branch until all i.dskp entries check
        and     word ptr [inode_flgs], 0EFFFh ; 1110111111111111b
		; bic $10000,i.flgs / clear large file bit
	mov	cx, 8
	xor	ax, ax
	mov	word ptr [inode_size], ax
		; clr i.size / zero file size
	;mov	di, offset inode_dskp
	rep	stosw ; jsr r0,copyz; i.dskp; i.dskp+16.
		      ; / zero block pointers
	
	call	set_imod  ; jsr	r0,setimod
			  ; / set i-node modified flag
	;mov	ax, word ptr [ii]  ; mov ii,r1
@@:
	retn	; rts	r0

itrunc endp


free proc near
        ; 01/12/2012
        ; unix boot file configuration version
	; of "free" procedure of retro unix v1.0 by Erdogan Tan
	; Derived from (original) UNIX v1 source code
	; PRELIMINARY release of Unix Implementation Document, 
	; 20/6/1972 
	; ('free' procedure)
	; 
	; INPUT -> ax (R1) = physical block number
	; Return -> CF = 0 -> Successed, CF = 1 -> failed
	;                               

	;push  bx     ; mov r2,-(sp) / save r2, r3
	;;push cx     ; mov r3,-(sp)
	;push  dx

	;call	free_3 ; jsr r0,3f 
		; / set up bit mask and word no. in free storage map
		; / for block
free_3: ; 3
	mov dx, 1    
	mov cx, ax   ; mov r1,r2 / block number, k, = 1
	and cx, 0Fh  ; bic $!7,r2 / clear all bits but 0,1,2; r2 = (k) mod (8)
		     ; clr r3
	jz short @f
		     ; bisb 2f(r2),r3 / use mask to set bit in r3 
		     ; corresponding to / (k) mod 8
	shl dx, cl
@@:
	mov bx, ax   ; mov r1,r2 / divide block number by 16
	shr bx, 1    ; asr r2	
	shr bx, 1    ; asr r2	
	shr bx, 1    ; asr r2	
	shr bx, 1    ; asr r2
		     ; bcc 1f / branch if bit 3 in r1 was 0 i.e., 	
		             ; bit for block is in / lower half of word
		     ; swab r3 / swap bytes in r3; bit in 
			      ; upper half of word in free / storage map		
free_1: ; 1
	shl bx, 1 ; asl	r2 / multiply block number by 2; r2 = k/8
	add bx, offset systm+2 ; add $systm+2,r2 
			  ; / address of word of free storage map for drum
	    		  ; / with block bit in it
	; retn  ; rts r0 (return from free_3)
@@:
	or word ptr [BX], dx  ; bis r3, (r2)
		  ; / set free storage block bit; indicates free block	
	; 0 -> allocated

	;;inc byte ptr [smod] ; incb smod / set super block modified for drum
	;mov byte ptr [smod], 1 ; / set super block modified for drum
	;pop dx
	;pop cx     ; mov (sp)+,r3 / restore r2, r3
	;pop bx     ; mov (sp)+,r2
	; AX (R1) = Block number

	retn

free endp


Cursor_Pos: dw 0

PhysicalDriveNumber: db 0
FileHandle: dw 0
StartupFile_Name: db 66 dup(0)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  messages
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

UNIX_Welcome:
                db 0Dh, 0Ah
                db 'Retro UNIX 8086 v1 Startup File Configuration Utility'
                db 0Dh, 0Ah
                db '(c) Erdogan TAN 2012 - [ 05/03/2013]'
                db 0Dh,0Ah
                db 0Dh,0Ah
                db 'Usage: unixboot [Floppy Drive] '
                db 0Dh,0Ah
                db 0Dh,0Ah
                db "Floppy Drive names:"
                db 0Dh,0Ah
                db 0Dh,0Ah
                db "fd0     (Floppy Disk 1, A:)", 0Dh, 0Ah
                db "fd1     (Floppy Disk 2, B:)", 0Dh, 0Ah
                db 0

Msg_DoYouWantToWrite:
                db 07h
                db 0Dh, 0Ah
                db 'Do you want to write Retro Unix v1 Startup File onto drive ', 0
UNIX_FD_Name:
                db 'fd'
UNIX_FD_Number:
                db '0: ', 0
msg_yes_no:
                db '(Yes/No)? ', 0

msg_unix_drv_read_error:
                db 0Dh, 0Ah
                db "Drive not ready or read error!"
                db 0Dh, 0Ah, 0

Msg_File_Not_Found:
                db 0Dh, 0Ah
                db "File not found !"
                db 0Dh, 0Ah, 0

Msg_Not_Unix_FS:
                db 0Dh, 0Ah
                db "Drive has not got a Retro UNIX v1 FS !"
                db 0Dh, 0Ah, 0

Msg_deleting_sf:
                db 0Dh, 0Ah
                db "Deleting Retro UNIX FS startup file..."
                db 0

Msg_writing_sf:
                db 0Dh, 0Ah
                db "Writing Retro UNIX FS startup file..."
                db 0

Msg_DosFile_Name:
                db 0Dh, 0Ah
                db "DOS File Name : ", 0

Msg_StartupFile_Name:
                db 0Dh, 0Ah
                db "Startup File Name : ", 0

Msg_3dot_OK:    db "..."
Msg_OK:
                db ' OK.', 0Dh, 0Ah, 0

msg_YES:        db ' YES'
                db 0
msg_NO:         db ' NO'
                db 0   

UNIX_CRLF:
                db 0Dh, 0Ah, 0

msg_unix_drv_write_error:
                db 0Dh, 0Ah
                db 'Drive not ready or write error!'
                db 0Dh, 0Ah
                db 0

msg_very_big_startup_file_size:
                db 0Dh, 0Ah
                db 'Very big boot file size !'
                db 0Dh, 0Ah
                db 0

msg_Startup_File_Exists:
                db 0Dh, 0Ah, 0Dh, 0Ah
                db 'Startup File is already configured ! '
msg_please_select_an_option:
               ;db 'Please select an option: '
                db 0Dh, 0Ah
                db 0Dh, 0Ah
                db 'Press <DELETE> to change current startup file configuration.'
		db 0Dh, 0Ah
                db 'Press <ENTER> to see current startup file information.'
		db 0Dh, 0Ah
                db 'Press <ESC> to exit.'
                db 0Dh, 0Ah, 0

msg_sf_configuration_reset_ok:
		; 01/12/2012
		db 0Dh, 0Ah
                db "Startup file configuration RESET is OK."
                db 0Dh, 0Ah, 0

msg_Delete_Startup_File:
		; 01/12/2012
                ;db 0Dh, 0Ah
		;db 'Please select an option: '
                ;db 0Dh, 0Ah
                db 0Dh, 0Ah
                db 'Press <ENTER> to reset startup file configuration without deleting file.'
		db 0Dh, 0Ah
                db 'Press <DELETE> to delete current startup file, also.'
		db 0Dh, 0Ah
                db 'Press <ESC> to cancel.'
                db 0Dh, 0Ah, 0

msg_overwrite_question1:
		; 1/12/2012
		db 0Dh, 0Ah
		db 'Do you want to overwrite '
		db 27h
		db 0

msg_overwrite_question2: 
		db 27h
		db ' file '
		db 0		

RetryCount:     dw 0

BOOT_FILE_NAME: db 9 dup(0)

bf_make_datetime: dd 0 ; 25/11/2012

bf_i_number: dw 0 ; 25/11/2012

bootfile_inode: 
inode:
inode_flgs:	dw 801Eh ; Flags (1000000000011110b)
inode_nlks:	db 1	; number of links 
inode_uid:	db 0	; user ID (0 = root)
inode_size:	dw 0	; file size
inode_dskp:	dw 8 dup (0) ; indirect or contents blocks
inode_ctim:	dd 0	; creation date & time
inode_mtim:	dd 0	; modification date & time
inode_reserved:	dw 0	; unused

rw: db 0

imod: db 0

U:
u_uid: db 0
u_namep: dw 0
u_dirp: dw 0
u_base: dw 0
u_off: dw 0
u_count: dw 0
u_nread: dw 0
u_dirbuf: db 10 dup(0)

ii: dw 0
buff_s: dw 0

year: dw 1970
month: dw 1
day: dw 1
hour: dw 0
minute: dw 0
second: dw 0

DMonth:
dw 0
dw 31
dw 59
dw 90
dw 120
dw 151
dw 181
dw 212
dw 243
dw 273
dw 304
dw 334

; 30/11/2012
;imin: dd 0
;ihrs: dd 0
;iday: dw 0
;lday: dw 0
;qday: dw 0
;iyrs: dw 0
;jday: dw 0
;mday: dw 0


; 25/11/2012
str_inode_number:
                db 0Dh, 0Ah
		db 'Startup File I-Number: ', 0
Decimal_i_no_str:		
		db 6 dup (0)

Str_startup_file_size:
                db 0Dh, 0Ah
                db 'Startup File Size : ', 0
Str_Bytes:
                db ' bytes', 0

Decimal_size_str: db 6 dup (0)

Str_sf_date_time:
                db 0Dh, 0Ah
                db 'Creating Date & Time    : '
Str_cday:	db '00'
		db '/'
Str_cmonth:	db '00'
                db '/'
Str_cyear:	db '0000'
                db 20h, 20h
Str_chour: 	db '00'
                db ':'
Str_cminute:  	db '00'
                db ':'
Str_csecond:  	db '00'
                db 0Dh, 0Ah
                db 'Last Modif. Date & Time : '
Str_mday:	db '00'
		db '/'
Str_mmonth:	db '00'
                db '/'
Str_myear:	db '0000'
                db 20h, 20h
Str_mhour: 	db '00'
                db ':'
Str_mminute:  	db '00'
                db ':'
Str_msecond:  	db '00'
                db 0Dh, 0Ah, 0

bootfile_CopyRight:

                db  '(c) Erdogan TAN - 09/07/2013'

                db  1 dup (0)

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  buffers
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
BSBUFFER:	db 512 dup(0)
systm: ; superblock
db 512 dup(0)
ReadBUFFER:     db 512 dup(0)
WriteBUFFER:	db 512 dup(0)


SizeOfFile      equ $-100

               
UNIXBOOT     ends

                end     START_CODE
