*** Variables ***
${initial_pc}                       0x0

*** Keywords ***
# WriteDoubleWord:  reversed bytes
# Disassembly output:  spaces between bytes
DisasTest BE
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0  ${triple}=null  ${alternateDialect}=False

    ${hex_addr}=                    Convert To Hex  ${hex_addr}  length=8  base=16

    ${b1}=                          Get Substring  ${hex_code}  0  2
    ${b2}=                          Get Substring  ${hex_code}  2  4
    ${b3}=                          Get Substring  ${hex_code}  4  6
    ${b4}=                          Get Substring  ${hex_code}  6  8

    ${b_write}=                     Set Variable  ${b4}${b3}${b2}${b1}
    ${b_disas}=                     Set Variable  ${b1}${b2}${b3}${b4}

    IF  ${code_size} > 4
        ${b_disas_4B+}=                 Write Extra Bytes BE And Return Their Expected Output  ${hex_addr}  ${hex_code}
    ELSE
        ${b_disas_4B+}=                 Set Variable  ${None}
    END
    ${b_disas}=                     Set Variable If  ${code_size} > 4  ${b_disas}${b_disas_4B+}  ${b_disas}

    DisasTest Core                  ${hex_addr}  ${b_write}  ${b_disas}  ${mnemonic}  ${operands}  ${code_size}  ${triple}  ${alternateDialect}

RoundTrip BE
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0  ${triple}=null  ${reverse}=True  ${alternateDialect}=False

    IF  ${reverse}
        ${expected}=                    Reverse Bytes  ${{$hex_code[:int($code_size) * 2]}}
    ELSE
        ${expected}=                    Set Variable  ${hex_code}
    END
    AsTest                          ${expected}  ${mnemonic}  ${operands}  ${triple}  0x${hex_addr}  ${alternateDialect}
    DisasTest BE                    ${hex_code}  ${mnemonic}  ${operands}  ${code_size}  ${hex_addr}  ${triple}  ${alternateDialect}

Write Extra Bytes BE And Return Their Expected Output
    [Arguments]                     ${hex_addr}  ${hex_code}

    ${int}=                         Convert To Integer  0x${hex_addr}
    ${int}=                         Evaluate  $int + 4
    ${adjusted_addr}=               Convert To Hex  ${int}

    ${b5}=                          Get Substring  ${hex_code}  8  10
    ${b6}=                          Get Substring  ${hex_code}  10  12
    ${b7}=                          Get Substring  ${hex_code}  12  14
    ${b8}=                          Get Substring  ${hex_code}  14  16

    Execute Command                 sysbus WriteDoubleWord 0x${adjusted_addr} 0x${b8}${b7}${b6}${b5}

    Return From Keyword             ${b5}${b6}${b7}${b8}

Reverse Bytes
    [Arguments]                     ${hex_str}  ${group_size}=${2}

    ${len}=                         Get Length  ${hex_str}
    ${out}=                         Create List
    FOR  ${i}  IN RANGE  0  ${len}  ${group_size}
        ${byte}=                        Get Substring  ${hex_str}  ${i}  ${{$i+$group_size}}
        Append To List                  ${out}  ${byte}
    END
    Reverse List                    ${out}

    [Return]                        ${{"".join($out)}}

# WriteDoubleWord:  reversed words
# Disassembly output:  space between words

DisasTest Thumb
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0

    ${hex_addr}=                    Convert To Hex  ${hex_addr}  length=8  base=16

    ${w1}=                          Get Substring  ${hex_code}  0  4
    ${w2}=                          Get Substring  ${hex_code}  4

    ${b_write}=                     Set Variable  ${w2}${w1}
    ${b_disas}=                     Set Variable  ${w1}${w2}

    # `flags` is an internal parameter use by Renode in LLVMArchitectureMapping.cs:GetTripleAndModelKey to choose
    # the correct LLVM triple that represents the ARM* processor's state:
    #  - bit 0 specifies whether we're in Thumb mode  -  both for ARMv7 and ARMv8
    #  - bit 1 specifies whether we're in AArch32/32-bit mode (when set) or AArch64/64-bit mode (when unset) for ARMv8
    # Since the ARMv7 branch only checks `flags > 0` to switch to Thumb, and the ARMv8 branch _requires_ both bits
    # to be set for Thumb mode (no 64-bit Thumb), we set flags to 3 = 0b11, ie. "32-bit Thumb", to guarantee Thumb mode
    DisasTest Core                  ${hex_addr}  ${b_write}  ${b_disas}  ${mnemonic}  ${operands}  ${code_size}  triple="thumb"

RoundTrip Thumb
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0

    # For Thumb, reverse the bytes in each word
    ${expected}=                    Reverse Bytes  ${hex_code}
    ${expected}=                    Reverse Bytes  ${expected}  group_size=${4}
    # See comment in `DisasTest Thumb` for meaning of flags
    AsTest                          ${expected}  ${mnemonic}  ${operands}  address=0x${hex_addr}  triple="thumb"
    DisasTest Thumb                 ${hex_code}  ${mnemonic}  ${operands}  ${code_size}  ${hex_addr}

DisasTest LE
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0

    ${hex_addr}=                    Convert To Hex  ${hex_addr}  length=8  base=16

    DisasTest Core                  ${hex_addr}  ${hex_code}  ${hex_code}  ${mnemonic}  ${operands}  ${code_size}

RoundTrip LE
    [Arguments]                     ${hex_code}  ${mnemonic}=  ${operands}=  ${code_size}=4  ${hex_addr}=0

    ${expected}=                    Reverse Bytes  ${{$hex_code[:int($code_size) * 2]}}
    AsTest                          ${expected}  ${mnemonic}  ${operands}  address=0x${hex_addr}
    DisasTest LE                    ${hex_code}  ${mnemonic}  ${operands}  ${code_size}  ${hex_addr}

DisasTest Core
    [Arguments]                     ${hex_addr}  ${code_write}  ${code_disas}  ${mnemonic}  ${operands}  ${code_size}  ${triple}=null  ${alternateDialect}=False

    Execute Command                 sysbus WriteDoubleWord 0x${hex_addr} 0x${code_write}
    ${res}=                         Execute Command  sysbus.cpu DisassembleBlock 0x${hex_addr} ${code_size} ${triple} ${alternateDialect}

    # expect error if "$mnemonic" and "$operands" (without curly brackets!) are empty
    Run Keyword And Return If       $mnemonic == '' and $operands == ''  Should Match Regexp  ${res}  Disassembly error detected

    # compare DisassembleBlock output with the expected one; "(?i)" prefix causes ignoring case difference
    ${escaped_mnem}=                Regexp Escape  ${mnemonic}
    ${escaped_oper}=                Regexp Escape  ${operands}
    Should Match Regexp             ${res}  (?i)^0x${hex_addr}:\\s+${code_disas}\\s+${escaped_mnem}\\s+${escaped_oper}\\n+$

AsTest
    [Arguments]                     ${expected}  ${mnemonic}  ${operands}=  ${triple}=null  ${address}=0  ${alternateDialect}=False

    ${len}=                         Execute Command  sysbus.cpu AssembleBlock ${address} "${mnemonic} ${operands}" ${triple} ${alternateDialect}
    ${bytes}=                       Execute Command  sysbus ReadBytes ${address} ${len}

    # This string is safe to eval because it's formatted as a Python list by PrintActionResult in MonitorCommands.cs
    ${hex_bytes}=                   Evaluate  "".join("%02x"%b for b in ${bytes})

    # Reverse the bytes for a big-endian bus because the expected strings in the test cases are formatted
    # as if they had been read by ReadDoubleWord
    ${bus_endian}=                  Execute Command  sysbus Endianess
    ${bus_endian}=                  Get Line  ${bus_endian}  0
    IF  "${bus_endian}" == "BigEndian"
        ${hex_bytes}=                   Reverse Bytes  ${hex_bytes}
    END

    Should Be Equal                 ${hex_bytes}  ${expected}

Execute Instruction
    [Arguments]                     ${instruction}
    Execute Command                 cpu PC ${initial_pc}
    Execute Command                 cpu AssembleBlock ${initial_pc} "${instruction}"
    Execute Command                 cpu Step 1

Memory Should Be Equal
    [Arguments]                     ${address}  ${value}
    ${res}=                         Execute Command  sysbus ReadDoubleWord ${address}
    Should Be Equal As Numbers      ${res}  ${value}

# Ordinary 'Register Should Be Equal  ${register_number}  ${value}' checks register with number one below than expected
Xtensa Register Should Be Equal
    [Arguments]                     ${register}  ${value}  ${cpu}=cpu
    ${res}=                         Execute Command  ${cpu} GetRegister '${register}'
    Should Be Equal As Numbers      ${value}  ${res}

Create Machine
    [Arguments]                     ${cpu}  ${model}

    # "extra" will be appended to the cpu creation string after cpuType (at least it has to close curly brackets opened before cpuType)
    ${extra}=                       Set Variable  }

    ${ARMv8_gic}=                   Set Variable  genericInterruptController: gic }; gic: IRQControllers.ARM_GenericInterruptController @ { sysbus new Bus.BusMultiRegistration { address: 0x8000000; size: 0x010000; region: \\"distributor\\" }; sysbus new IRQControllers.ArmGicRedistributorRegistration { attachedCPU: cpu; address: 0x80a0000 } } { [0-1] -> cpu@[0-1]; architectureVersion: .GICv3; supportsTwoSecurityStates: true }
    # the last ${extra} field covers the "else" case, keeping the previous value of "extra"; by default, "else" case sets variables to "None"
    ${extra}=                       Set Variable If  "${cpu}" == "CortexM"  ; nvic: nvic }; nvic: IRQControllers.NVIC  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "ARMv8A"  ; ${ARMv8_gic}  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "ARMv8R"  ; ${ARMv8_gic}  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "PowerPc64"  ; endianness: Endianess.LittleEndian }  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "RiscV32"  ; timeProvider: empty }  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "RiscV64"  ; timeProvider: empty }  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "X86"  ; lapic: empty }  ${extra}
    ${extra}=                       Set Variable If  "${cpu}" == "X86_64"  ; lapic: empty }  ${extra}

    Execute Command                 mach create
    IF  any(x in "${cpu}" for x in ("PowerPc", "Sparc"))
        Execute Command                 machine LoadPlatformDescriptionFromString "sysbus: { Endianess: Endianess.BigEndian }"
    END
    Execute Command                 machine LoadPlatformDescriptionFromString "cpu: CPU.${cpu} @ sysbus { cpuType: \\"${model}\\" ${extra}"
    Execute Command                 machine LoadPlatformDescriptionFromString "mem: Memory.MappedMemory @ sysbus 0x0 { size: 0x50000 }"

Assemble And Disassemble RV32IMA
    [Arguments]                     ${compressed}=False

    # Compressed format will be generated by the assembler if the core has the C extension
    # and is only accepted by the disassembler if the core has the C extension. The disassembler
    # output doesn't explicitly indicate the compressed instruction (c.sw, c.add)
    IF  ${compressed}
        RoundTrip LE                    c84a  sw  s2, 16(sp)  2  # rv32c
        RoundTrip LE                    95be  add  a1, a1, a5  2  # rv32c
    ELSE
        RoundTrip LE                    01212823  sw  s2, 16(sp)  # rv32i
        RoundTrip LE                    00b785b3  add  a1, a5, a1  # rv32i
    END

    # The uncompressed forms should be accepted by the disassembler even with the C extension
    DisasTest LE                    01212823  sw  s2, 16(sp)  # rv32i
    DisasTest LE                    00b785b3  add  a1, a5, a1  # rv32i

    RoundTrip LE                    00008297  auipc  t0, 8  # rv32i
    RoundTrip LE                    0000100f  fence.i  # Zifencei
    RoundTrip LE                    3401f173  csrrci  sp, mscratch, 3  # Zicsr
    RoundTrip LE                    02ab5c33  divu  s8, s6, a0  # rv32m
    RoundTrip LE                    0805252f  amoswap.w  a0, zero, (a0)  # rv32a

Assemble And Disassemble RV32FD
    RoundTrip LE                    580123d3  fsqrt.s  ft7, ft2, rdn  # rv32f
    RoundTrip LE                    5a0123d3  fsqrt.d  ft7, ft2, rdn  # rv32d

Assemble And Disassemble RV32C
    RoundTrip LE                    3fed  jal  -6  2  # rv32c

Assemble And Disassemble RV64IMAC
    RoundTrip LE                    000a3a83  ld  s5, 0(s4)  # rv64i
    RoundTrip LE                    abcd8a9b  addiw  s5, s11, -1348  # rv64i
    RoundTrip LE                    02ab7c3b  remuw  s8, s6, a0  # rv64m
    RoundTrip LE                    e705b52f  amomaxu.d.aqrl  a0, a6, (a1)  # rv64a
    RoundTrip LE                    eabc  sd  a5, 80(a3)  2  # rv64c

Assemble And Disassemble RV64FD
    RoundTrip LE                    d0312353  fcvt.s.lu  ft6, sp, rdn  # rv64f
    RoundTrip LE                    d2312353  fcvt.d.lu  ft6, sp, rdn  # rv64d

Assemble And Disassemble RVV
    RoundTrip LE                    00057757  vsetvli  a4, a0, e8, m1, tu, mu  # rv64v
    RoundTrip LE                    03058407  vle8ff.v  v8, (a1)  # rv64v
    RoundTrip LE                    4218a757  vfirst.m  a4, v1  # rv64v

*** Test Cases ***
# Keywords to disassemble single instruction
#
# DisasTest (BE|LE|Thumb)  HEX_CODE  [MNEMONIC]  [OPERANDS]  [CODE_SIZE=4]  [HEX_ADDR=00000000]
#  HEX_CODE  the opcode to disassemble; don't prefix with "0x"
#  MNEMONIC, OPERANDS  expected disassembly results; expect empty result if both are empty
#  CODE_SIZE  in bytes; max 8B instructions are supported
#  HEX_ADDR  hex address of the instruction, verified with the disassembler output but not influencing the opcode itself; don't prefix with "0x"

Should Assemble And Disassemble ARM Cortex-A
    [Tags]                          basic-tests
    Create Machine                  ARMv7A  arm926ej-s

    RoundTrip LE                    32855001  addlo  r5, r5, \#1  hex_addr=8000
    RoundTrip LE                    e1b00a00  lsls  r0, r0, \#20  hex_addr=813c
    RoundTrip LE                    1a00000a  bne  \#40

Should Assemble And Disassemble ARM Cortex-A53
    Create Machine                  ARMv8A  cortex-a53

    RoundTrip LE                    5400f041  b.ne  \#7688
    RoundTrip LE                    aa0603e1  mov  x1, x6
    RoundTrip LE                    aa2c1c65  orn  x5, x3, x12, lsl \#7

Should Assemble And Disassemble ARM Cortex-M
    Create Machine                  CortexM  cortex-m4

    RoundTrip Thumb                 f0230403  bic  r4, r3, \#3  hex_addr=2
    RoundTrip Thumb                 58c8  ldr  r0, [r1, r3]  2
    RoundTrip Thumb                 f44f426d  mov.w  r2, \#60672  hex_addr=9e8
    RoundTrip Thumb                 10b6  asrs  r6, r6, \#2  2  ad88

Should Assemble And Disassemble ARM Cortex-R52
    Create Machine                  ARMv8R  cortex-r52

    RoundTrip LE                    e320f000  nop
    RoundTrip LE                    43855040  orrmi  r5, r5, #64
    RoundTrip LE                    e6ff3072  uxth  r3, r2
    RoundTrip Thumb                 eb750903  sbcs.w  r9, r5, r3
    RoundTrip Thumb                 ebb272e1  subs.w  r2, r2, r1, asr #31
    RoundTrip Thumb                 fb821002  smull  r1, r0, r2, r2

Should Assemble And Disassemble RISCV32IMA
    [Tags]                          basic-tests
    Create Machine                  RiscV32  rv32ima
    Assemble And Disassemble RV32IMA

Should Assemble And Disassemble RISCV32IMAC
    Create Machine                  RiscV32  rv32imac
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32C

Should Assemble And Disassemble RISCV32IMAFDC
    Create Machine                  RiscV32  rv32imafdc
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32FD
    Assemble And Disassemble RV32C

Should Assemble And Disassemble RISCV32GC
    Create Machine                  RiscV32  rv32gc
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32FD
    Assemble And Disassemble RV32C

Should Assemble And Disassemble RISCV32GC_XANDES
    Create Machine                  RiscV32  rv32gc_xandes
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32FD
    Assemble And Disassemble RV32C

Should Assemble And Disassemble RISCV32GV
    Create Machine                  RiscV32  rv32gv
    Assemble And Disassemble RV32IMA
    Assemble And Disassemble RVV

Should Assemble And Disassemble RISCV64IMAC
    Create Machine                  RiscV64  rv64imac
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV64IMAC

Should Assemble And Disassemble RISCV64IMAFDC
    Create Machine                  RiscV64  rv64imafdc
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32FD
    Assemble And Disassemble RV64IMAC
    Assemble And Disassemble RV64FD

Should Assemble And Disassemble RISCV64GC
    Create Machine                  RiscV64  rv64gc
    Assemble And Disassemble RV32IMA  compressed=True
    Assemble And Disassemble RV32FD
    Assemble And Disassemble RV64IMAC
    Assemble And Disassemble RV64FD

Should Assemble And Disassemble RISCV64GCV
    Create Machine                  RiscV64  rv64gcv
    Assemble And Disassemble RV64IMAC
    Assemble And Disassemble RVV

Should Assemble And Disassemble PPC
    [Tags]                          basic-tests
    Create Machine                  PowerPc  e200z6

    RoundTrip LE                    4800007c  b  .+124
    RoundTrip LE                    7f880040  cmplw  7, 8, 0  hex_addr=123
    RoundTrip LE                    7ce40034  cntlzw  4, 7

Should Assemble And Disassemble PPC64 LE
    [Tags]                          basic-tests
    Create Machine                  PowerPc64  620

    # RoundTrip BE is used because of the output formatting in DisasTest BE
    # CPU is set as LE in Renode and LLVM's LE version of ppc64 is used
    RoundTrip BE                    18002389  lbz  9, 24(3)
    RoundTrip BE                    40202a7c  cmpld  10, 4
    RoundTrip BE                    71790248  bl  .+162160

Should Assemble And Disassemble Sparc
    [Tags]                          basic-tests
    Create Machine                  Sparc  leon3

    RoundTrip LE                    85e8a018  restore  %g2, 24, %g2  hex_addr=abc
    RoundTrip LE                    01000000  nop  hex_addr=abc
    RoundTrip LE                    10680047  ba  %xcc, 71

Should Assemble And Disassemble X86 Using Intel Syntax
    [Tags]                          basic-tests
    Create Machine                  X86  x86

    RoundTrip BE                    6b7b0c14  imul  edi, dword ptr [ebx + 12], 20  alternateDialect=True  reverse=False
    RoundTrip BE                    45  inc  ebp  1  alternateDialect=True  reverse=False
    RoundTrip BE                    0fb7c0  movzx  eax, ax  3  cc  alternateDialect=True  reverse=False
    RoundTrip BE                    66890cc516a9fd00  mov  word ptr [8*eax + 16623894], cx  8  a  alternateDialect=True  reverse=False
    RoundTrip BE                    0f011d5e00fc00  lidtd  [16515166]  7  abd  alternateDialect=True  reverse=False

Should Assemble And Disassemble X86 Using GAS Syntax
    [Tags]                          basic-tests
    Create Machine                  X86  x86

    RoundTrip BE                    6b7b0c14  imull  $20, 12(%ebx), %edi  reverse=False
    RoundTrip BE                    45  incl  %ebp  1  reverse=False
    RoundTrip BE                    0fb7c0  movzwl  %ax, %eax  3  cc  reverse=False
    RoundTrip BE                    66890cc516a9fd00  movw  %cx, 16623894(,%eax,8)  8  a  reverse=False
    RoundTrip BE                    0f011d5e00fc00  lidtl  16515166  7  abd  reverse=False

Should Assemble And Disassemble X86_64 Using Intel Syntax
    [Tags]                          basic-tests
    Create Machine                  X86_64  x86_64

    RoundTrip BE                    676b7b0c14  imul  edi, dword ptr [ebx + 12], 20  5  alternateDialect=True  reverse=False
    # Only testing assembly here as the disassembly-testing keywords can handle at most 8 bytes of code.
    AsTest                          48b8f0debc8a67452301  movabs  rax, 81985529234382576  alternateDialect=True
    RoundTrip BE                    48890cc516a9fd00  mov  qword ptr [8*rax + 16623894], rcx  8  alternateDialect=True  reverse=False
    RoundTrip BE                    48ffc0  inc  rax  3  alternateDialect=True  reverse=False
    RoundTrip BE                    65488b06  mov  rax, qword ptr gs:[rsi]  alternateDialect=True  reverse=False

Should Assemble And Disassemble X86_64 Using GAS Syntax
    [Tags]                          basic-tests
    Create Machine                  X86_64  x86_64

    RoundTrip BE                    676b7b0c14  imull  $20, 12(%ebx), %edi  5  reverse=False
    AsTest                          48b8f0debc8a67452301  movabsq  $81985529234382576, %rax
    RoundTrip BE                    48890cc516a9fd00  movq  %rcx, 16623894(,%rax,8)  8  reverse=False
    RoundTrip BE                    48ffc0  incq  %rax  3  reverse=False
    RoundTrip BE                    65488b06  movq  %gs:(%rsi), %rax  reverse=False

Should Assemble And Disassemble Xtensa
    Create Machine                  Xtensa  sample_controller

    RoundTrip BE                    802160  abs  a2, a8  3  reverse=False
    RoundTrip BE                    301280  add  a1, a2, a3  3  reverse=False
    RoundTrip BE                    f02000  nop  ${EMPTY}  3  reverse=False
    RoundTrip BE                    27811b  bany  a1, a2, . +31  3  reverse=False
    RoundTrip BE                    c60600  j  . +31  3  reverse=False
    RoundTrip BE                    050000  call0  . +4  3  reverse=False
    # Test Xtensa 'dense' option
    RoundTrip BE                    1812  l32i.n  a1, a2, 4  2  reverse=False
    RoundTrip BE                    1922  s32i.n  a1, a2, 8  2  reverse=False
    RoundTrip BE                    0df0  ret.n  ${EMPTY}  2  reverse=False
    RoundTrip BE                    0df0  ret.n  ${EMPTY}  2  reverse=False

Should Assemble And Execute Xtensa
    Create Machine                  Xtensa  sample_controller

    Execute Instruction             movi.n a1, 0x10
    Xtensa Register Should Be Equal  A1  0x10

    ${A1}=                          Set Variable  0x1234
    ${A2}=                          Set Variable  0x5432
    Execute Command                 cpu SetRegister 'A1' ${A1}
    Execute Command                 cpu SetRegister 'A2' ${A2}
    Execute Instruction             add a3, a1, a2
    Xtensa Register Should Be Equal  A3  0x6666

    ${arbitrary_jump_target}=       Set Variable  0x10
    Execute Command                 cpu SetRegister 'A1' ${arbitrary_jump_target}
    Execute Instruction             jx a1
    PC Should be Equal              ${arbitrary_jump_target}

    ${some_value}=                  Set Variable  0x11223344
    Execute Command                 cpu SetRegister 'A1' 0x100
    Execute Command                 sysbus WriteDoubleWord 0x100 ${some_value}
    Execute Instruction             l32i.n a2, a1, 0
    Xtensa Register Should Be Equal  A2  ${some_value}

    ${some_value}=                  Set Variable  0x88112233
    Execute Command                 cpu SetRegister 'A0' ${some_value}
    Execute Command                 cpu SetRegister 'A1' 0x100
    Execute Instruction             s32i.n a0, a1, 0
    Memory Should Be Equal          0x100  ${some_value}

Should Handle Illegal Instruction When Disassembling
    Create Machine                  RiscV64  rv64g

    DisasTest LE                    0
    DisasTest LE                    0000

Should Handle Disassembly From Invalid Address
    Create Machine                  RiscV64  rv64g

    # test with the valid address
    DisasTest LE                    02051613  slli  a2, a0, 32  hex_addr=1234

    # check whether the output contains error if we only change the address to be outside "mem"
    Run Keyword And Expect Error    'Disassembly error detected*  DisasTest LE  02051613  slli  a2, a0, 32  hex_addr=02000000

Should Take Base Address Into Account When Assembling
    Create Machine                  X86  x86

    AsTest                          8d0534120000  a: lea  eax, [a]  address=0x1234  alternateDialect=True
    AsTest                          8d053a120000  lea  eax, [a]; a:  address=0x1234  alternateDialect=True

Should Assemble Multiline Program
    ${prog}=                        Catenate  SEPARATOR=\n
    ...                             nop
    ...                             nop

    Create Machine                  X86  x86

    Execute Command                 sysbus.cpu AssembleBlock 0 "${prog}"

    ${ins}=                         Execute Command  sysbus ReadWord 0

    Should Be Equal As Numbers      ${ins}  0x9090

Should Handle Illegal Instruction When Assembling
    Create Machine                  RiscV64  rv64g

    Run Keyword And Expect Error    *unrecognized instruction mnemonic*  AsTest  00  illegalinstruction123
    Run Keyword And Expect Error    *invalid operand*  AsTest  00  sw s123, 0(sp)
    # The V extension is not in rv64g so this is illegal as well
    Run Keyword And Expect Error    *instruction requires * 'V'*  AsTest  00  vsetvli a4, a0, e8, m1, tu, mu

Should Handle Assembler Directives
    Create Machine                  X86  x86

    AsTest                          909090909090  .rept 6; nop; .endr
