.global _start

.text
_start:

    # lui
    lui     x1, 0xfedcb         # x1  = 0xfedcb000

    # addi
    addi    x1, x1, 0x789       # x1  = 0xfedcb789
    addi    x2, x0, -1          # x2  = 0xffffffff
    addi    x3, x1, -0x777      # x3  = 0xfedcb012

    # add
    add     x4, x1, x2          # x4  = 0xfedcb788

    # sub
    sub     x5, x1, x3          # x5  = 0x00000777
    
    # and
    and     x6, x1, x2          # x6  = 0xfedcb789
    and     x7, x1, x0          # x7  = 0x00000000
    and     x8, x4, x3          # x8  = 0xfedcb000

    # or
    or      x9, x1, x2          # x9  = 0xffffffff
    or      x10, x1, x0         # x10 = 0xfedcb789
    or      x11, x4, x3         # x11 = 0xfedcb79a

    # xor
    xor     x12, x1, x2         # x12 = 0x01234876
    xor     x13, x1, x1         # x13 = 0x00000000
    xor     x14, x0, x2         # x14 = 0xffffffff

    # andi
    andi    x15, x2, -1348      # x15 = 0xfffffabc      -1348 = 0xfffffabc
    andi    x16, x2, 0x123      # x16 = 0x00000123
    andi    x17, x1, -1645      # x17 = 0xfedcb181      -1645 = 0xfffff993

    # ori
    ori     x18, x2, 0x000      # x18 = 0xffffffff
    ori     x19, x0, 0x768      # x19 = 0x768
    ori     x20, x1, 0x7ff      # x20 = 0xfedcb7ff

    # xori
    xori    x21, x2, 0x123      # x21 = 0xfffffedc
    xori    x22, x1, 0x788      # x22 = 0xfedcb001
    xori    x23, x0, 0x788      # x23 = 0x00000788

    # slli
    slli    x24, x23, 4         # x24 = 0x00007880
    slli    x25, x2, 1          # x25 = 0xfffffffe
    slli    x27, x2, 31         # x27 = 0x80000000

    # srli
    srli    x28, x23, 4         # x28 = 0x00000078
    srli    x29, x2, 1          # x29 = 0x7fffffff
    srli    x3, x2, 31          # x3  = 0x00000001

    # srai
    srai    x4, x23, 4          # x4  = 0x00000078
    srai    x5, x2, 1           # x5  = 0xffffffff
    srai    x7, x2, 31          # x7  = 0xffffffff

    # sll
    addi    x8, x0, 4           # x8  = 0x00000004
    addi    x9, x0, 1           # x9  = 0x00000001
    addi    x10, x0, 63         # x10 = 0x0000003f
    addi    x11, x0, 31         # x11 = 0x0000001f
    sll     x12, x23, x8        # x12 = 0x00007880      # 4
    sll     x13, x2, x9         # x13 = 0xfffffffe      # 1
    sll     x14, x2, x10        # x14 = 0x80000000      # 63 = 31
    sll     x15, x2, x11        # x15 = 0x80000000      # 31
    sll     x16, x1, x0         # x16 = 0xfedcb789      # 0
    sll     x17, x1, x2         # x17 = 0x80000000      # -1=31

    # srl
    srl     x18, x23, x8        # x18 = 0x00000078      # 4
    srl     x19, x2, x9         # x17 = 0x7fffffff      # 1
    srl     x20, x2, x10        # x20 = 0x00000001      # 63 = 31
    srl     x21, x2, x11        # x21 = 0x00000001      # 31
    srl     x22, x1, x0         # x22 = 0xfedcb789      # 0
    srl     x24, x1, x2         # x24 = 0x00000001      # -1=31

    # sra
    sra     x25, x23, x8        # x25 = 0x00000078      # 4
    sra     x26, x2, x9         # x26 = 0xffffffff      # 1
    sra     x27, x2, x10        # x27 = 0xffffffff      # 63 = 31
    sra     x28, x2, x11        # x28 = 0xffffffff      # 31
    sra     x29, x1, x0         # x29 = 0xfedcb789      # 0
    sra     x30, x1, x2         # x30 = 0xffffffff      # -1=31

    # slti
    addi    x3, x0, 1           # x3  = 0x00000001
    addi    x4, x0, 0x010       # x4  = 0x00000010
    addi    x5, x0, 0x100       # x5  = 0x00000100
    sub     x6, x0, x3          # x6  = 0xffffffff
    sub     x7, x0, x4          # x7  = 0xfffffff0
    sub     x8, x0, x5          # x8  = 0xffffff00
    slti    x9, x3, 0           # x9  = 0x00000000
    slti    x10, x3, 1          # x10 = 0x00000000
    slti    x11, x3, 2          # x11 = 0x00000001
    slti    x12, x3, -1         # x12 = 0x00000000
    slti    x13, x7, 0          # x13 = 0x00000001
    slti    x14, x7, -17        # x14 = 0x00000000

    # sltiu
    sltiu   x15, x3, 0          # x15 = 0x00000000
    sltiu   x16, x3, 1          # x16 = 0x00000000
    sltiu   x17, x3, 2          # x17 = 0x00000001
    sltiu   x18, x3, -1         # x18 = 0x00000001      # -1=0xffffffff
    sltiu   x19, x7, 0          # x19 = 0x00000000
    sltiu   x20, x7, -15        # x20 = 0x00000001      # -15=0xfffffff1

    # slt
    slt     x21, x0, x3         # x21 = 0x00000001
    slt     x22, x3, x0         # x22 = 0x00000000
    slt     x23, x3, x3         # x23 = 0x00000000
    slt     x24, x3, x6         # x24 = 0x00000000
    slt     x25, x6, x3         # x25 = 0x00000001

    # sltu
    sltu    x26, x0, x3         # x26 = 0x00000001
    sltu    x27, x3, x0         # x27 = 0x00000000
    sltu    x28, x3, x3         # x28 = 0x00000000
    sltu    x29, x3, x6         # x29 = 0x00000001
    sltu    x30, x6, x3         # x30 = 0x00000000

    # auipc
    auipc   x3, 0               # x3  = pc + 0
    auipc   x4, 3               # x4  = pc + 0x3000
    auipc   x5, 0xfffff         # x5  = pc + 0xfffff000
    # TODO: verify auipc adds and does not concatenate (must have PC>0xfff to test this)

    # jal
    jal     x1, test_jalr

test1:
    # beq
    addi    x30, x0, 1          # x30 = 1
    addi    x9, x8, 0           # x9  = 0xffffff00
    bne     x0, x0, fail        # 0 == 0
    bne     x9, x8, fail        # x9 == x8
    bne     x7, x8, test1_done  # x7 != x8
    j       fail
test1_done:

test2:
    # beq
    addi    x30, x0, 2          # x30 = 2
    beq     x0, x8, fail        # 0 != x8
    beq     x7, x8, fail        # x7 != x8
    beq     x8, x9, test2_done  # x8 == x9
    j       fail
test2_done:

test3:
    # blt
    addi    x30, x0, 3          # x30 = 3
    blt     x8, x9, fail        # x8 == x9
    blt     x7, x8, fail        # x7 > x8
    blt     x30, x8, fail       # x30 > x8
    blt     x8, x7, test3_done  # x8 < x7
    j       fail
test3_done:

test4:
    # bltu
    addi    x30, x0, 4          # x30 = 4
    bltu    x8, x9, fail        # x8 == x9
    bltu    x7, x8, fail        # x7 > x8
    bltu    x30, x8, test4_done # x30 < x8 unsigned
    j       fail
test4_done:

test5:
    addi    x30, x0, 5          # x30 = 5
    bltu    x8, x7, test5_done  # x8 < x7
    j       fail
test5_done:

test6:
    # bne
    addi    x30, x0, 6          # x30 = 6
    bne     x0, x0, fail        # 0 == 0
    bne     x8, x9, fail        # 0 == 0
    bne     x8, x0, test6_done  # x8 != 0
    j       fail
test6_done:

test7:
    # bge
    addi    x30, x0, 7          # x30 = 7
    bge     x8, x7, fail        # x8 < x7
    bge     x7, x7, test7_done  # x7 == x7
    j       fail
test7_done:

test8:
    addi    x30, x0, 8          # x30 = 8
    bge     x8, x0, fail        # x8 < 0
    bge     x7, x8, test8_done  # x7 > x8
    j       fail
test8_done:

test9:
    # bgeu
    addi    x30, x0, 9          # x30 = 9
    bgeu    x8, x7, fail        # x8 < x7
    bgeu    x0, x8, fail        # 0 < x8 unsigned
    bgeu    x8, x0, test9_done  # x8 > 0 unsigned
    j       fail
test9_done:

test10:
    addi    x30, x0, 10          # x30 = 10
    # now for some memory stuff
    # sw
    la      x9, someint         # x9  = 
    lui     x10, 0x12345        # x10 = 0x12345000
    addi    x10, x10, 0x678     # x10 = 0x12345678
    nop
    nop
    nop
    nop
    nop
    lw      x11, 0(x9)          # x11 = 0xfedcba98  # TODO: do something with this
    nop
    nop
    nop
    nop
    nop
    sw      x10, 0(x9)          # someint = 0x12345678
    nop
    nop
    nop
    nop
    nop
    lw      x12, 0(x9)          # x12 = 0x12345678
    nop
    nop
    nop
    nop
    nop
    bne     x12, x10, fail
test10_done:

test11:
    addi    x30, x0, 11         # x30 = 11
    addi    x5, x0, 0           # x5  = 0
    addi    x6, x0, 0x10        # x6  = 0x00000010 = 16
test11_loop:
    nop
    nop
    nop
    nop
    nop
    sw      x10, 0(x9)
    addi    x10, x10, 1         # x10 = x10 + 1
    addi    x9, x9, 4           # x9  = x9 + 4
    addi    x5, x5, 1           # x5  = x5 + 1
    blt     x5, x6, test11_loop
test11_done:

test12:
    addi    x30, x0, 12
test12_loop:
    # decrement values before load since they were incremented after final store
    addi    x10, x10, -1        # x10 = x10 - 1
    addi    x9, x9, -4          # x9  = x9 - 4
    addi    x5, x5, -1          # x5 = x5 - 1
    nop
    nop
    nop
    nop
    nop
    lw      x11, 0(x9)
    bne     x11, x10, fail
    bgt     x5, x0, test12_loop
test12_done:

test13:
    addi    x30, x0, 13         # x30 = 13
    addi    x8, x9, 4
    addi    x12, x10, 1
    lw      x11, 4(x9)
    bne     x11, x12, fail
    addi    x8, x9, 8
    addi    x12, x10, 2
    lw      x11, 8(x9)
    bne     x11, x12, fail
    addi    x8, x9, 0xc
    addi    x12, x10, 3
    lw      x11, 0xc(x9)
    bne     x11, x12, fail
    addi    x8, x9, 0x10
    addi    x12, x10, 4
    lw      x11, 0x10(x9)
    bne     x11, x12, fail
    addi    x8, x9, 0x14
    addi    x12, x10, 5
    lw      x11, 0x14(x9)
    bne     x11, x12, fail
test13_done:


done:
    la      x31, failcode       # x30 = 
    addi    x30, x0, 0xff       # x31 = 0x000000ff
    slli    x30, x30, 8         # x31 = 0x0000ff00
    addi    x30, x30, 0xff      # x31 = 0x0000ffff
    slli    x30, x30, 8         # x31 = 0x00ffff00
    addi    x30, x30, 0xff      # x31 = 0x00ffffff
    slli    x30, x30, 8         # x31 = 0xffffff00
    addi    x30, x30, 0xff      # x31 = 0xffffffff
    # slli    x30, x30, 1         # x31 = 0xfffffffe // this should cause a fail
    nop
    nop
    nop
    nop
    nop
    sw      x30, 0(x31)         # failcode = 0xffffffff
    nop
    nop
    nop
    nop
    nop

    lui     x30, 0x10101        # x30 = 0x10101000
    addi    x30, x30, 0x010     # x30 = 0x10101010

    # set registers to known values before loop
    addi    x2, x0, 1           # x2 = 1
    addi    x3, x0, 1           # x3 = 1
    addi    x4, x0, 1           # x4 = 1
    addi    x5, x0, 1           # x5 = 1
    addi    x6, x0, 1           # x6 = 1

loop_init:
    # counter and infinite loop
    addi    x31, x0, 1          # x1 = 1

loop:
    addi    x31, x31, 1         # increment x1
    jal     x1, loop            # loop forever
    addi    x2, x0, 0           # NOTE: this should never be executed
    addi    x3, x0, 0           # NOTE: this should never be executed
    addi    x4, x0, 0           # NOTE: this should never be executed
    addi    x5, x0, 0           # NOTE: this should never be executed
    addi    x6, x0, 0           # NOTE: this should never be executed
    nop
    nop
    nop
    nop
    nop
    nop

fail:
    la      x31, failcode       # x31 =
    nop
    nop
    nop
    nop
    nop
    sw      x30, 0(x31)         # failcode = test number
    nop
    nop
    nop
    nop
    nop
    # set some registers to make it blatantly obvious an error occurred
    addi    x1, x0, 0x7ff       # x1 = 0x1111
    addi    x2, x0, 0x7ff       # x1 = 0x1111
    addi    x3, x0, 0x7ff       # x1 = 0x1111
    addi    x4, x0, 0x7ff       # x1 = 0x1111
    addi    x5, x0, 0x7ff       # x1 = 0x1111
    addi    x6, x0, 0x7ff       # x1 = 0x1111
    addi    x7, x0, 0x7ff       # x1 = 0x1111
    addi    x8, x0, 0x7ff       # x1 = 0x1111
    addi    x9, x0, 0x7ff       # x1 = 0x1111
    j       fail                # loop forever
    nop
    nop
    nop
    nop
    nop
    nop

    # jalr
test_jalr:
    addi    x2, x0, 0x12        # x2 = 0x12
    jalr    x0, x1, 0           # return
    nop
    nop
    nop
    nop
    nop
    nop


.data
failcode:
    .word 0x00000000
someint:
    .word 0xfedcba98
someint16:
    .hword 0x1122
someint8:
    .byte 0xaa
anotherint8:
    .byte 0xbb

.bss
anotherint:
    .word