    ; SPDX-FileCopyrightText: 2025 Leo Marušić <leomarusic7@gmail.com>
    ; SPDX-License-Identifier: MIT
    MAIN:
     MOV SP, #0x10000       ; stack initialization
     LDR R0, MEM            ; pointer to the address of the operands
     LDR R12, REZ           ; pointer for the result address
    MAINLOOP:
     ADD R0, R0, #0x8       ; point to the operation in the operand block
     LDR R1, [R0]           ; save the operation code in R1
     CMP R1, #0x0           ; check for subtraction
     BEQ SUBTRACT
     CMP R1, #0x1           ; check for addition
     BEQ ADDLOOP
     CMP R1, #0x2           ; check for multiplication
     BEQ MULLOOP
     CMP R1, #0x3           ; check for division
     BEQ DIVIDEOP
     MVN R2, #0x0           ; put 0xFFFFFFFF in R2
     CMP R1, R2             ; check for the end
     BEQ FINISH
     B MAINLOOP             ; go back to the loop

    SUBTRACT:
     SUB R0, R0, #0x8   ; go back to the beginning of the operand block
     LDR R1, [R0]       ; load the first operand
     LDR R2, [R0, #0x4] ; load the second operand
     SUB R3, R1, R2     ; subtract
     STR R3, [R12]      ; save the result
     ADD R12, R12, #0x4 ; move the result address pointer
     ADD R0, R0, #0xC   ; move the operand address pointer
     B MAINLOOP

    ADDLOOP:
     SUB R0, R0, #0x8   ; go back to the beginning of the operand block
     LDR R1, [R0]       ; load the first operand
     LDR R2, [R0, #0x4] ; load the second operand
     ADD R3, R1, R2     ; add
     STR R3, [R12]      ; save the result
     ADD R12, R12, #0x4 ; move the result address pointer
     ADD R0, R0, #0xC   ; move the operand address pointer
     B MAINLOOP

    MULLOOP:
     SUB R0, R0, #0x8   ; go back to the beginning of the operand block
     LDR R1, [R0]       ; load the first operand
     LDR R2, [R0, #0x4] ; load the second operand
     MUL R3, R1, R2     ; multiply
     STR R3, [R12]      ; save the result
     ADD R12, R12, #0x4 ; move the result address pointer
     ADD R0, R0, #0xC   ; move the operand address pointer
     B MAINLOOP

    DIVIDEOP:
     SUB R0, R0, #0x8   ; go back to the beginning of the operand block
     LDR R1, [R0]       ; load the first operand
     LDR R2, [R0, #0x4] ; load the second operand
     SUB SP, SP, #0x4   ; space for the result
     STMFD SP!, {R1-R2} ; put the operands on the stack
     BL DIVIDE
     ADD SP, SP, #0x8   ; stack cleanup
     LDMFD SP!, {R3}    ; retrieve the result
     STR R3, [R12]      ; save the result
     ADD R12, R12, #0x4 ; move the result address pointer
     ADD R0, R0, #0xC   ; move the operand address pointer
     B MAINLOOP

    DIVIDE:
     STMFD SP!, {R3-R5}       ; save the context
     LDR R3, [SP, #12]        ; load the numerator
     LDR R4, [SP, #16]        ; load the denominator
     MOV R5, #0               ; quotient
     CMP R4, #0x0             ; check for division by zero
     BEQ ZERO

     CMP R3, #0               ; check if the numerator is negative
     MVNLT R3, R3             ; 1's complement
     ADDLT R3, R3, #1         ; 2's complement
     CMP R4, #0               ; check if the denominator is negative
     MVNLT R4, R4             ; 1's complement
     ADDLT R4, R4 , #1        ; 2's complement

    LOOP1:
     CMP R3, R4         ; compare the numerator and the denominator
     BLT DONE           ; if the numerator is less than the denominator, the division is finished
     SUB R3, R3, R4     ; subtract the denominator from the numerator
     ADD R5, R5, #1     ; increment the quotient
     B LOOP1

    DONE:
     CMP R1, #0         ; check the sign of the original numerator
     MVNLT R5, R5       ; 1's complement the quotient
     ADDLT R5, R5, #1   ; 2's complement the quotient
     CMP R2, #0         ; check the sign of the original denominator
     MVNLT R5, R5       ; 1's complement the quotient
     ADDLT R5, R5 , #1  ; 2's complement the quotient
     STR R5, [SP, #20]  ; put the result on the stack
     LDMFD SP!, {R3-R5} ; restore the context
     MOV PC, LR

    ZERO:
     STR R5, [SP, #20]  ; save zero as the result on the stack
     LDMFD SP!, {R3-R5} ; restore the context
     MOV PC, LR

    FINISH:
     MVN R11, #0x0      ; marker for the end of the output
     STR R11, [R12]     ; save the marker at the end of the output
     SWI 0x123456

    MEM: DW 0x600       ; Memory for the operands
     ORG 0x600
     DW 0xFFFFFEFF
     DW 0x00000010
     DW 0x00000003

     DW 0x000001F4
     DW 0xFFFFFD44
     DW 0x00000000

     DW 0x00000003
     DW 0xFFFFFFEC
     DW 0x00000001

     DW 0xFFFFFFFE
     DW 0x0000000A
     DW 0x00000002

     DW 0xFFFFF000
     DW 0xFFFFFFC0
     DW 0x00000003

     DW 0x00000001
     DW 0x00000004
     DW 0xFFFFFFFF

    RES: DW 0x2000       ; memory for the result
     ORG 0x2000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000
     DW 0x0000