; Test Program using all opcodes

START:
    NOP                 ; No operation (does nothing, advances to the next instruction)
    MOV R1, 0x10        ; Move immediate value 0x10 to register R1
    MOV R2, R1          ; Move value from R1 to R2
    MOV [0x2000], R3    ; Load value from memory address 0x2000 into R3
    MOV R1, [0x2000]    ; Store R1 value to memory address 0x2000
    SWAP R1, R2         ; Swap values between R1 and R2
    SWAPN R1            ; Swap nibbles within R1
    ADD R1, R2          ; Add R2 to R1
    ADD R1, 0x10        ; Add immediate 0x10 to R1
    SUB R1, R2          ; Subtract R2 from R1
    SUB R1, 0x10        ; Subtract immediate 0x10 from R1
    MUL R1, R2          ; Multiply R1 by R2
    MUL R1, 0x10        ; Multiply R1 by immediate 0x10
    DIV R1, R2          ; Divide R1 by R2
    DIV R1, 0x10        ; Divide R1 by immediate 0x10
    MOD R1, R2          ; Compute remainder of R1 / R2
    MOD R1, 0x10        ; Compute remainder of R1 / 0x10
    NEG R1              ; Negate R1
    AND R1, R2          ; Bitwise AND of R1 and R2
    AND R1, 0x10        ; Bitwise AND R1 with immediate 0x10
    OR R1, R2           ; Bitwise OR of R1 and R2
    OR R1, 0x10         ; Bitwise OR R1 with immediate 0x10
    XOR R1, R2          ; Bitwise XOR of R1 and R2
    XOR R1, 0x10        ; Bitwise XOR R1 with immediate 0x10
    NOT R1              ; Bitwise NOT of R1
    SHL R1, 2           ; Logical shift left R1 by 2 bits
    SHR R1, 2           ; Logical shift right R1 by 2 bits
    SAR R1, 2           ; Arithmetic shift right R1 by 2 bits (sign extended)
    JMP 0x3000          ; Jump to address 0x3000
    JMP +5              ; Jump 5 bytes forward
    INC R1              ; Increment R1
    INC [0x2000]        ; Increment value at memory address 0x2000
    DEC R1              ; Decrement R1
    DEC [0x2000]        ; Decrement value at memory address 0x2000
    CMP R1, R2          ; Compare R1 and R2 (sets flags based on R1 - R2)
    JE 0x4000           ; Jump to 0x4000 if equal (zero flag set)
    JNE 0x4000          ; Jump to 0x4000 if not equal (zero flag not set)
    JG 0x4000           ; Jump to 0x4000 if greater
    JL 0x4000           ; Jump to 0x4000 if less
    JGE 0x4000          ; Jump to 0x4000 if greater or equal
    JLE 0x4000          ; Jump to 0x4000 if less or equal
    CALL 0x5000         ; Call subroutine at 0x5000
    RET                 ; Return from subroutine
    JMPBC R1, 3, 0x4000 ; Jump to address 0x4000 if bit 3 in register R1 is not set
    JMPBC 0x2000, 5, 0x5000 ; Jump to address 0x5000 if bit 5 in memory at address 0x2000 is not set
    JMPBS R2, 1, 0x6000 ; Jump to address 0x6000 if bit 1 in register R2 is set
    JMPBS 0x3000, 7, 0x7000 ; Jump to address 0x7000 if bit 7 in memory at address 0x3000 is set

; Halt the program
HLT
