org 0x7c00                  ; BIOS load address

start:
    ; Initialize the processor (not explicitly done in the code, usually BIOS job)
    ; Initialize the serial port
    mov ah, 0x00            ; Set COM port initialization function
    mov al, 0x03            ; Baud rate divisor for 9600 baud
    mov dx, 0               ; COM1 port number (0 for COM1)
    int 0x14                ; Call BIOS COM interrupt

    ; 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
    jmp main_loop

store_byte:
    call read_address       ; Get address from the serial port
    call read_byte          ; Get a byte from the serial port
    mov [bx], al            ; Store the byte at that address
    jmp main_loop

call_subroutine:
    call read_address       ; Get address from the serial port
    call far [bx]           ; Call the subroutine at that address
    jmp main_loop           ; Return to the main loop after subroutine

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
    ret

read_byte:                  ; Function to read a byte from the serial port
    mov dx, 0x3f8           ; COM1 base address
wait_for_data:
    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
    mov ah, al              ; Move byte to AH for sending
    mov dx, 0               ; COM1 port number (0 for COM1)
    int 0x14                ; Call BIOS COM interrupt
    pop ax                  ; Restore AX register
    ret

; The print_byte and nibble_to_ascii functions are not necessary for the goals
; and have been removed to simplify the code.

times 510-($-$$) db 0       ; Pad remaining bytes with zeros
dw 0xaa55                   ; Boot signature
