; FASM 3 Words FORTH. 

org 0x7c00                  ; BIOS load address

start:
    ; Initialize COM port 1 with a baud rate of 9600
    call init_uart

    ; Clear the screen
    mov ax, 0x0003          ; Set video mode to 80x25 text mode
    int 0x10	

main_loop:
    call read_byte          ; Read a byte from the serial port
    cmp al, 0x01            ; Check if byte = 01 [fetch]
    je fetch_byte
    cmp al, 0x02            ; Check if byte = 02 [store]
    je store_byte
    cmp al, 0x03            ; Check if byte = 03 [call]
    je call_subroutine
    jmp main_loop           ; Loop back if none of the above

fetch_byte:
    call read_address       ; Get address from the serial port
    mov al, [bx]            ; Fetch the byte from that address
    call send_byte          ; Send the byte to the serial port
    call print_byte         ; Print the byte to the screen
    jmp main_loop

store_byte:
    call read_address       ; Get address from the serial port
    call read_byte          ; Get a byte from the serial port
    call print_byte         ; Print the byte to the screen
    mov [bx], al            ; Store the byte at that address
    jmp main_loop

call_subroutine: 
    call read_address       ; Get address from the serial port
    push bx                 ; Push return address on stack
    push ax                 ; Push other registers as needed
    ; ... (push other registers as needed)
    call bx                 ; Call the subroutine
    ; ... (pop other registers as needed)
    pop ax                  ; Restore registers
    pop bx                  ; Restore return address
    jmp main_loop

read_address:               ; Function to read an address from the serial port
    call read_byte          ; Read low byte
    mov bl, al
    call read_byte          ; Read high byte
    mov bh, al
    ; Alternative: swap bl and bh if the address comes in reverse order
    ret

read_byte:					; Function to read a byte from the serial port
    call read_byte_from_com1  ; Read a byte from UART COM1
    ret
	
wait_for_data:
    mov dx, 0x3f8 + 5       ; Update dx to point to the line status register
    in al, dx               ; Read line status register
    test al, 1              ; Test if data available (bit 0)
    jz wait_for_data        ; If not, loop until data is available
    mov dx, 0x3f8           ; Reset dx to point to the data register
    in al, dx               ; Read received byte from data register
    ret

send_byte:                  ; Function to send a byte to the serial port
    push ax                ; Save AX register
    call send_byte_to_com1 ; AL already contains the byte to be sent
    pop ax                 ; Restore AX register
    ret

; Helper function to print a single nibble in hexadecimal
print_nibble:
    push ax                 ; Save AX register
    and al, 0x0F            ; Ensure we're only dealing with the lower nibble
    cmp al, 9
    ja .convert_to_letter   ; For A-F, adjust the ASCII value
    add al, '0'             ; For 0-9, directly convert to ASCII
    jmp .print
.convert_to_letter:
    add al, 'A' - 10        ; Convert 10-15 to 'A'-'F'
.print:
    mov ah, 0x0E            ; BIOS teletype function
    int 0x10                ; Print character
    pop ax                  ; Restore AX register
    ret

; Convert and print a byte in AL to hexadecimal
print_byte:
    push ax            ; Save AX register to preserve the byte value for later
    push bx            ; Save BX register because we'll use it

    ; Print 'Received:'
    mov ah, 0x0E       ; Prepare for printing characters
    mov si, received_msg  ; SI points to the start of the 'Received:' message
.print_received_loop:
    lodsb              ; Load byte at SI into AL, automatically increments SI
    test al, al        ; Zero-flag set if AL is zero (end of string)
    jz .after_print_received  ; Jump out of loop if at end of string
    int 0x10           ; Print character in AL
    jmp .print_received_loop  ; Loop back to print next character
.after_print_received:

    ; Print space before hexadecimal value
    mov al, ' '
    int 0x10

    ; Print the hexadecimal value of the original byte (restored from stack)
    pop bx             ; Restore the original byte into BX, as AL is used for printing
    mov al, bh         ; Move the high nibble of the byte to be printed into AL
    call print_nibble  ; Convert and print high nibble

    mov al, bl         ; Move the low nibble of the byte to be printed into AL
    call print_nibble  ; Convert and print low nibble

    pop bx             ; Restore BX register, AX was not pushed again so no need to pop it
    ret

received_msg db 'Received: ', 0


; Convert a nibble in BL to ASCII and print
nibble_to_ascii:
    add bl, 0x90            ; Convert to ASCII (0-9, A-F)
    daa                     ; Adjust for BCD
    adc bl, 0x40            ; Adjust for ASCII ('A'-'F')
    daa                     ; Final adjustment
    mov ah, 0x0e            ; BIOS teletype output
    int 0x10                ; Call BIOS video interrupt
    ret
	
; Includes : 
include 'com1.asm'

times 510-($-$$) db 0       ; Pad remaining bytes with zeros
dw 0xaa55                   ; BIOS boot signature