Write to console
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 5 Aug 2024 15:36:54 +0000 (16:36 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 5 Aug 2024 15:36:54 +0000 (16:36 +0100)
build/chimaera.img
build/chimaera.vhd
src/Makefile.unix
src/apps/hello/Makefile.unix
src/apps/hello/hello.asm
src/kernel/int21.asm
src/lib/crt/include/stdio.inc
src/lib/crt/stdio/fputc.asm [new file with mode: 0644]
src/lib/crt/stdio/fwrite.asm [new file with mode: 0644]

index 759b6197612384af68ee2b86871c1b7fefb655a1..c5dc8e7cfdbc5070a8ea341100aff353f6d767aa 100644 (file)
Binary files a/build/chimaera.img and b/build/chimaera.img differ
index f3a04cbe879f8acffdc1701f63627400b7bd2736..dcb9b66214d61b4c4710436cc3349bbaea786129 100644 (file)
Binary files a/build/chimaera.vhd and b/build/chimaera.vhd differ
index ad0e40e3e88fba55085845191a502813acc47921..7c0b071ef2e71aade084d03623dac0552897ada1 100644 (file)
@@ -46,6 +46,7 @@ chimaera.vhd: all
        utils/dosfstools/mcopy --arca --offset 17 -i $@ boot/freeldr/core/freeldr.sys ::
        utils/dosfstools/mcopy --arca --offset 17 -i $@ kernel/kernel.sys ::
        utils/dosfstools/mcopy --arca --offset 17 -i $@ apps/pcomm/pcomm.com ::command.com
+#      utils/dosfstools/mcopy --arca --offset 17 -i $@ apps/hello/hello.com ::hello.com
 
 run-qemu: chimaera.img chimaera.vhd
 #      qemu-system-i386 -cpu 486 -drive file="chimaera.img",format=raw,if=floppy,index=0 -m 4M
index 07d771fdd732995fbd08e89a9e825712d69d0280..14cc2039acdc84d7bfc1e1c79b1e2e6f3a15c488 100644 (file)
@@ -18,4 +18,4 @@ hello.com: ../../lib/crt/crt0.o crlf.o hello.o writechr.o writehex.o writestr.o
        ../../utils/binutils/slink --oformat msdos -o $@ $^
 
 %.o: %.asm
-       ../../utils/binutils/sasm -l $*.lst -o $@ $<
+       ../../utils/binutils/sasm -I$(SRCDIR)/../../lib/crt/include -l $*.lst -o $@ $<
index cea0de6be7d19ada0f7c3db991da5ee4d0978df0..ff2b84e329334577764a0bd1974ec43abc61f095 100644 (file)
@@ -5,6 +5,11 @@
 % define        HEX(y)                  0x##y
 %endif
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include stdio.inc.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <stdio.inc>
+
 ;******************************************************************************
 ; @function         _free
 ;******************************************************************************
@@ -12,10 +17,10 @@ global      _main
 _main:
 
     mov     bx,     offset msg_hello
-    
     call    _writestr
-    call    _crlf
-    
+
+;    call    _crlf
+;    
 ;    mov     ah,     HEX (08)
 ;    int     HEX (21)
 ;    
@@ -30,28 +35,80 @@ _main:
 ;    
 ;    xor     ax,     ax
 ;    int     HEX (16)
-    
-    mov     ah,     HEX (39)
-    mov     dx,     offset _dir_non_exist
-    int     HEX (21)
-    
-    call    _writehex
-    call    _crlf
-    
-    mov     ah,     HEX (39)
-    mov     dx,     offset _dir_exist
-    int     HEX (21)
-    
-    call    _writehex
-    call    _crlf
-    
-    mov     ah,     HEX (39)
-    mov     dx,     offset _dir_file
-    int     HEX (21)
-    
-    call    _writehex
-    call    _crlf
-    
+;    
+;    mov     ah,     HEX (39)
+;    mov     dx,     offset _dir_non_exist
+;    int     HEX (21)
+;    
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     ah,     HEX (39)
+;    mov     dx,     offset _dir_exist
+;    int     HEX (21)
+;    
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     ah,     HEX (39)
+;    mov     dx,     offset _dir_file
+;    int     HEX (21)
+;    
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     si,     offset msg_hello
+;    xor     ax,     ax
+;    
+;    mov     bx,     stdout
+;
+;.loop:
+;
+;    lodsb
+;    
+;    and     al,     al
+;    jz      .exit
+;    
+;    push    bx
+;    push    ax
+;    
+;    call    _fputc
+;    add     sp,     4
+;    
+;    jmp     .loop
+;
+;    mov     bx,     1
+;    mov     cx,     15
+;    mov     dx,     offset msg_hello
+;    
+;    mov     ax,     stdout
+;    push    ax
+;    
+;    push    cx
+;    push    bx
+;    push    dx
+;    
+;    call    _fwrite
+;    add     sp,     8
+;    
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     ax,     stdout
+;    push    ax
+;    
+;    push    bx
+;    push    cx
+;    push    dx
+;    
+;    call    _fwrite
+;    add     sp,     8
+;    
+;    call    _writehex
+;    call    _crlf
+
+.exit:
+
     xor     ax,     ax
     ret
 
@@ -59,7 +116,3 @@ _main:
 ;; Data area.
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 msg_hello:                      db      "Hello, world!",        HEX (0D),   HEX (0A),   HEX (00)
-
-_dir_non_exist:                 db      "abc\\123",             HEX (00)
-_dir_exist:                     db      "temp",                 HEX (00)
-_dir_file:                      db      "hello.com",            HEX (00)
index cb56f0420d330815b02326634c3092aae9f909c3..d9bf5f0e450e029ea30a64a75f6062abfe396e0b 100644 (file)
@@ -860,6 +860,12 @@ _int21_dispatch.list:
     db      HEX (3F)
     dw      _int21_3F
     
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Write to File or Device Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (40)
+    dw      _int21_40
+    
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;; Delete/Unlink File.
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2518,6 +2524,237 @@ _int21_3F.done:
     
     jmp     iretc
 
+;******************************************************************************
+; @function         _int21_40
+; @brief            Write to File or Device Using Handle
+;
+; @in               BX -> File handle..
+; @in               CX -> Number of bytes to write.
+; @in               DS:DX -> Pointer to write buffer.
+;
+; @out              AX -> Number of written.  Error code if CF is set.
+;******************************************************************************
+_int21_40:
+
+    push    bp
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First, lets check if we're writing to the console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     2
+    ja      _int21_40.check
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If stdin was passed then we can't write to it.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _int21_40.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Otherwise, lets write the bytes.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     dx
+
+_int21_40.console_loop:
+
+    and     cx,     cx
+    jz      _int21_40.done
+    
+    lodsb
+    call    _writechr
+    
+    dec     cx
+    jmp     _int21_40.console_loop
+
+_int21_40.check:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _int21_40.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _int21_40.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    cx
+    
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    pop     cx
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then the file handle is invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _int21_40.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-initialize the extra segment but this time with the address
+    ;; of the vector entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+
+_int21_40.copy:
+
+    push    si
+    push    ds
+    push    ax
+    push    cx
+    
+    mov     ds,     ax
+    xor     si,     si
+    
+    lodsw
+    mov     cs:[_curr_cluster],     ax
+    
+    lodsw
+    mov     cs:[_curr_cluster + 2],     ax
+    
+    mov     di,     offset _fat_bpb
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     cx,     25
+    rep     movsb
+    
+    lodsb
+    mov     cs:[_drive_no],     al
+    
+    lodsw
+    mov     cs:[_root_cluster],     ax
+    
+    lodsw
+    mov     cs:[_root_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_fat_start],    ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_root_start],   ax
+    
+    lodsw
+    mov     cs:[_root_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_data_start],   ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_fat_secmask],      ax
+    
+    lodsw
+    mov     cs:[_fat_secshift],     ax
+    
+    lodsw
+    mov     cs:[_clustsize],    ax
+    
+    lodsw
+    mov     cs:[_info_sector],      ax
+    
+    mov     bx,     cs:[_root_cluster]
+    mov     cx,     cs:[_root_cluster + 2]
+    
+    or      bx,     cx
+    
+    and     bx,     bx
+    jnz     _int21_40.fat32
+    
+    call    _getfattype
+    jmp     _int21_40.write
+
+_int21_40.fat32:
+
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _find_free32
+    mov     cs:[_find_free],    ax
+    
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],         ax
+    
+    mov     ax,     offset _update_cluster32
+    mov     cs:[_update_cluster],       ax
+
+_int21_40.write:
+
+    pop     cx
+    pop     ax
+    pop     ds
+    pop     si
+    
+    mov     es,     ax
+
+_int21_40.error:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    mov     ax,     6
+    stc
+    
+    jmp     iretc
+
+_int21_40.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    mov     ax,     cx
+    clc
+    
+    jmp     iretc
+
 ;******************************************************************************
 ; @function         _int21_42
 ; @brief            Move File Pointer Using Handle
index 165b10ac3192ddfaeff0a83029a55c255bc00b72..701b5e34497313dffc757fd798ac65788f19693e 100644 (file)
 %define     __SEOF                      0x0020
 %define     __SAPP                      0x0100
 
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Console file pointers.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     stdin                       0x0001
+%define     stdout                      0x0002
+%define     stderr                      0x0003
+
 %endif      ; _STDIO_INC
diff --git a/src/lib/crt/stdio/fputc.asm b/src/lib/crt/stdio/fputc.asm
new file mode 100644 (file)
index 0000000..401b2a8
--- /dev/null
@@ -0,0 +1,158 @@
+;******************************************************************************
+; @file             fputc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fputc
+;******************************************************************************
+global      _fputc
+_fputc:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the character off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    mov     [_buffer],      al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the file stream off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 6]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a file stream.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _fputc.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're 2 or 3 then we're writing to the console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     2
+    jb      _fputc.error
+    
+    cmp     bx,     3
+    ja      _fputc.check
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the value to get the correct file number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Write the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (40)
+    mov     cx,     1
+    mov     dx,     offset _buffer
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was a carry then we failed.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _fputc.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Otherwise we succeeded.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _fputc.done
+
+_fputc.check:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     bx
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Write the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (40)
+    mov     cx,     1
+    mov     dx,     offset _buffer
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was a carry then we failed.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _fputc.error
+
+_fputc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fputc.error:
+
+    xor     ax,     -1
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_buffer:                        db      2       dup (0)
diff --git a/src/lib/crt/stdio/fwrite.asm b/src/lib/crt/stdio/fwrite.asm
new file mode 100644 (file)
index 0000000..3d7f92d
--- /dev/null
@@ -0,0 +1,225 @@
+;******************************************************************************
+; @file             fread.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _fwrite
+;******************************************************************************
+global      _fwrite
+_fwrite:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the reserved stack value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the file handle off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 10]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _fwrite.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're 2 or 3 then we're writing to the console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     2
+    jb      _fwrite.error
+    
+    cmp     bx,     3
+    ja      _fwrite.check
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the value to get the correct file number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the amount of bytes to read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the number of bytes are zero then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     cx,     cx
+    jz      _fwrite.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the number of bytes into the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the dx register with the address of the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Write # no of bytes from the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (40)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was a carry then we failed.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _fwrite.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Otherwise we succeeded.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _fwrite.check2
+
+_fwrite.check:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the amount of bytes to read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the number of bytes are zero then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     cx,     cx
+    jz      _fwrite.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     bx
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the number of bytes into the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the dx register with the address of the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Write # no of bytes from the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (40)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was a carry then we failed.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _fwrite.error
+
+_fwrite.check2:
+
+    cmp     word ptr [bp + 8],      1
+    jne     _fwrite.check3
+    
+    cmp     ax,     word ptr [bp + 6]
+    jne     _fwrite.zero
+    
+    mov     ax,     1
+    jmp     _fwrite.done
+
+_fwrite.check3:
+
+    cmp     word ptr [bp - 6],      1
+    je      _fwrite.done
+    
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    div     cx
+    
+    jmp     _fwrite.done
+
+_fwrite.zero:
+
+    xor     ax,     ax
+
+_fwrite.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fwrite.error:
+
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret