387 lines
20 KiB
Plaintext
387 lines
20 KiB
Plaintext
*** Settings ***
|
|
Test Setup Create Machine
|
|
Test Tags atomics
|
|
|
|
*** Variables ***
|
|
${MEMORY_START} 0x80000000
|
|
${PLATFORM_STRING} SEPARATOR=\n
|
|
... dram: Memory.MappedMemory @ sysbus ${MEMORY_START} {
|
|
... ${SPACE*4}size: 0x80000000
|
|
... }
|
|
... mmio: Memory.ArrayMemory @ sysbus 0x100000000 {
|
|
... ${SPACE*4}size: 0x10000
|
|
... }
|
|
... mtvec: Memory.MappedMemory @ sysbus 0x1000 { size: 0x40000 }
|
|
...
|
|
... cpu: CPU.RiscV64 @ sysbus {
|
|
... ${SPACE*4}cpuType: "rv64gc_zicsr_zifencei_zacas";
|
|
... ${SPACE*4}hartId: 1;
|
|
... ${SPACE*4}privilegedArchitecture: PrivilegedArchitecture.Priv1_10;
|
|
... ${SPACE*4}timeProvider: empty;
|
|
... ${SPACE*4}CyclesPerInstruction: 8;
|
|
... ${SPACE*4}allowUnalignedAccesses: true
|
|
... }
|
|
...
|
|
... cpu32: CPU.RiscV32 @ sysbus {
|
|
... ${SPACE*4}cpuType: "rv32gc_zicsr_zifencei_zacas";
|
|
... ${SPACE*4}hartId: 2;
|
|
... ${SPACE*4}privilegedArchitecture: PrivilegedArchitecture.Priv1_10;
|
|
... ${SPACE*4}timeProvider: empty;
|
|
... ${SPACE*4}CyclesPerInstruction: 8;
|
|
... ${SPACE*4}allowUnalignedAccesses: true
|
|
... }
|
|
${PROGRAM_COUNTER} 0x80000000
|
|
${PROGRAM_COUNTER_32} 0x80000100
|
|
${ORDINARY_ADDRESS} 0x80001000
|
|
${MAX_PAGE_SIZE} 0x40000000 # 1 GiB
|
|
${PAGE_SPANNING_ADDRESS} ${{str(${MEMORY_START} + ${MAX_PAGE_SIZE} - 1)}} # str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${MMIO_ADDRESS} 0x0000000100001000
|
|
|
|
${mtvec} 0x1010
|
|
${illegal_instruction} 0x2
|
|
|
|
# Registers used
|
|
${x0} 0
|
|
${a0} 10
|
|
${a1} 11
|
|
${a2} 12
|
|
${a3} 13
|
|
${a4} 14
|
|
${s2} 18
|
|
|
|
# 32-, 64- and 128-bit constants
|
|
${wrong_expected_128} 0x12345678910111213141516171819202
|
|
${wrong_expected_64} 0x1234567891011
|
|
${wrong_expected_32} 0x1234
|
|
${expected_128} 0x2badc00010ffb0ba1afedeadbeefd00d
|
|
${expected_64} 0x1afedeadbeefd00d
|
|
${expected_32} 0xbeefd00d
|
|
${new_128} 0x216b00b5d0d0caca1eeff00dbabedead
|
|
${new_64} 0xbeeff00dbabedead
|
|
${new_32} 0xbeefbabe
|
|
|
|
*** Keywords ***
|
|
Create Machine
|
|
Execute Command mach create
|
|
Execute Command machine LoadPlatformDescriptionFromString """${PLATFORM_STRING}"""
|
|
Execute Command cpu ExecutionMode SingleStep
|
|
Execute Command cpu PC ${PROGRAM_COUNTER}
|
|
Execute Command cpu32 ExecutionMode SingleStep
|
|
Execute Command cpu32 PC ${PROGRAM_COUNTER}
|
|
|
|
Get Cpu On ${platform:(RV32|RV64)}
|
|
IF "${platform}" == "RV32"
|
|
${cpu}= Set Variable cpu32
|
|
ELSE IF "${platform}" == "RV64"
|
|
${cpu}= Set Variable cpu
|
|
END
|
|
[return] ${cpu}
|
|
|
|
Amocas.${size:(w|d|q)} ${rd} ${rs2} ${rs1} On ${platform:(RV32|RV64)} Should Throw Illegal Instruction
|
|
${cpu}= Get Cpu On ${platform}
|
|
|
|
# Should have jumped to mtvec
|
|
PC Should Be Equal ${mtvec} cpuName=${cpu}
|
|
|
|
# The cause should be illegal instruction.
|
|
${mcause}= Execute Command ${cpu} MCAUSE
|
|
Should Be Equal As Numbers ${mcause} ${illegal_instruction}
|
|
|
|
# MTVAL should be the opcode that caused the fault.
|
|
${mtval}= Execute Command ${cpu} MTVAL
|
|
${illegal_amocas_opcode}= Assemble Amocas.${size} ${rd} ${rs2} ${rs1}
|
|
Should Be Equal As Numbers ${mtval} ${illegal_amocas_opcode}
|
|
|
|
# MEPC should point to the illegal instruction.
|
|
${mepc}= Execute Command ${cpu} MEPC
|
|
Should Be Equal As Numbers ${mepc} ${PROGRAM_COUNTER}
|
|
|
|
Amocas.${size:(w|d|q)} Memory Location ${address} Should Now Be Set To ${value}
|
|
IF "${size}" == "w"
|
|
${current_value}= Execute Command sysbus ReadDoubleWord ${address}
|
|
ELSE IF "${size}" == "d"
|
|
${current_value}= Execute Command sysbus ReadQuadWord ${address}
|
|
ELSE IF "${size}" == "q"
|
|
${current_value_lower}= Execute Command sysbus ReadQuadWord ${address}
|
|
${current_value_upper}= Execute Command sysbus ReadQuadWord ${${address} + 8}
|
|
END
|
|
|
|
IF "${size}" == "q"
|
|
${new_value_lower}= Set Variable ${{str(int(${value}) & 0xFFFFFFFFFFFFFFFF)}}
|
|
${new_value_upper}= Set Variable ${{str((int(${value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}}
|
|
Should Be Equal As Integers ${current_value_lower} ${new_value_lower} "Memory location lower should now be set to ${new_value_lower}"
|
|
Should Be Equal As Integers ${current_value_upper} ${new_value_upper} "Memory location upper should now be set to ${new_value_upper}"
|
|
ELSE
|
|
Should Be Equal As Integers ${current_value} ${value} "Memory location ${address} should now be set to ${value} but it's ${current_value}"
|
|
END
|
|
|
|
Amocas.${size:(w|d|q)} Register ${register} On ${platform:(RV32|RV64)} Should Contain ${expected_value}
|
|
${cpu}= Get Cpu On ${platform}
|
|
|
|
IF "${platform}" == "RV32" and "${size}" == "d"
|
|
# str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${expected_value_lower}= Set Variable ${{str(int(${expected_value}) & 0xFFFFFFFF)}}
|
|
${expected_value_upper}= Set Variable ${{str((int(${expected_value}) >> 32) & 0xFFFFFFFF)}}
|
|
Register Should Be Equal ${register} ${expected_value_lower} cpuName=${cpu}
|
|
Register Should Be Equal ${${register} + 1} ${expected_value_upper} cpuName=${cpu}
|
|
ELSE IF "${platform}" == "RV64" and "${size}" == "q"
|
|
# str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${expected_value_lower}= Set Variable ${{str(int(${expected_value}) & 0xFFFFFFFFFFFFFFFF)}}
|
|
${expected_value_upper}= Set Variable ${{str((int(${expected_value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}}
|
|
Register Should Be Equal ${register} ${expected_value_lower} cpuName=${cpu}
|
|
Register Should Be Equal ${${register} + 1} ${expected_value_upper} cpuName=${cpu}
|
|
ELSE
|
|
Register Should Be Equal ${register} ${expected_value} cpuName=${cpu}
|
|
END
|
|
|
|
Amocas.${size:(w|d|q)} Set Register ${register} On ${platform:(RV32|RV64)} To ${value}
|
|
${cpu}= Get Cpu On ${platform}
|
|
|
|
IF "${register}" == "0"
|
|
Return From Keyword
|
|
END
|
|
|
|
IF "${platform}" == "RV32" and "${size}" == "d"
|
|
${value_lower}= Set Variable ${{${value} & 0xFFFFFFFF}}
|
|
${value_upper}= Set Variable ${{(${value} >> 32) & 0xFFFFFFFF}}
|
|
Execute Command ${cpu} SetRegister ${register} ${value_lower}
|
|
Execute Command ${cpu} SetRegister ${${register} + 1} ${value_upper}
|
|
ELSE IF "${platform}" == "RV64" and "${size}" == "q"
|
|
# str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${value_lower}= Set Variable ${{str(int(${value}) & 0xFFFFFFFFFFFFFFFF)}}
|
|
${value_upper}= Set Variable ${{str((int(${value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}}
|
|
Execute Command ${cpu} SetRegister ${register} ${value_lower}
|
|
Execute Command ${cpu} SetRegister ${${register} + 1} ${value_upper}
|
|
ELSE
|
|
Execute Command ${cpu} SetRegister ${register} ${value}
|
|
END
|
|
|
|
Assemble Amocas.${size:(w|d|q)} ${rd} ${rs2} ${rs1}
|
|
# Hand-assembled instructions necessary due to
|
|
# our version of the LLVM assembler not supporting the Zacas extension. (issue #74345)
|
|
|
|
# The machine code for an amocas instruction with its operands and size zeroed out.
|
|
${amocas_base}= Set Variable 0b00101_0_0_00000_00000_000_00000_0101111
|
|
|
|
# Translate size mnemonic to corresponding bit pattern.
|
|
IF "${size}" == "w"
|
|
${size_bits}= Set Variable 0b010
|
|
ELSE IF "${size}" == "d"
|
|
${size_bits}= Set Variable 0b011
|
|
ELSE IF "${size}" == "q"
|
|
${size_bits}= Set Variable 0b100
|
|
END
|
|
|
|
# Insert size into instruction
|
|
${amocas_sized}= Set Variable ${{${amocas_base} | (${size_bits} << 12)}}
|
|
|
|
# Insert rd operand
|
|
${amocas_sized_rd}= Set Variable ${{${amocas_sized} | (${rd} << 7)}}
|
|
|
|
# Insert rs1 operand
|
|
${amocas_sized_rd_rs1}= Set Variable ${{${amocas_sized_rd} | (${rs1} << 15)}}
|
|
|
|
# Insert rs2 operand
|
|
${amocas_complete}= Set Variable ${{${amocas_sized_rd_rs1} | (${rs2} << 20)}}
|
|
|
|
[return] ${amocas_complete}
|
|
|
|
Amocas.${size:(w|d|q)} On ${platform:(RV32|RV64)} ${should:(Should|Shouldn't)} Set Value At ${variable_address} To ${new_value} If Expecting ${expected_value}
|
|
[Arguments]
|
|
... ${rd}=${a0}
|
|
... ${rs1}=${a3}
|
|
... ${rs2}=${s2}
|
|
... ${original_value_upper}=0x2badc00010ffb0ba
|
|
... ${original_value_lower}=${expected_64}
|
|
|
|
# Place value in memory.
|
|
Execute Command sysbus WriteQuadWord ${variable_address} ${original_value_lower}
|
|
Execute Command sysbus WriteQuadWord ${${variable_address} + 8} ${original_value_upper}
|
|
|
|
${cpu}= Get Cpu On ${platform}
|
|
|
|
# Construct amocas instruction.
|
|
${MACHINE_CODE_AMOCAS}= Assemble Amocas.${size} ${rd} ${rs2} ${rs1}
|
|
|
|
IF "${size}" == "w"
|
|
# str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${ORIGINAL_VALUE_MASKED}= Set Variable ${{str(${original_value_lower} & 0xFFFFFFFF)}}
|
|
ELSE IF "${size}" == "d"
|
|
${ORIGINAL_VALUE_MASKED}= Set Variable ${original_value_lower}
|
|
ELSE IF "${size}" == "q"
|
|
# str necessary since robot's XML-RPC library doesn't support >32-bit integers
|
|
${ORIGINAL_VALUE_MASKED}= Set Variable "${{str((${original_value_upper} << 64) | ${original_value_lower})}}"
|
|
END
|
|
|
|
# Place machine code at PC.
|
|
Execute Command sysbus WriteDoubleWord ${PROGRAM_COUNTER} ${MACHINE_CODE_AMOCAS}
|
|
|
|
# Set operand values.
|
|
Amocas.${size} Set Register ${rd} On ${platform} To ${expected_value}
|
|
Amocas.${size} Set Register ${rs1} On ${platform} To ${variable_address}
|
|
Amocas.${size} Set Register ${rs2} On ${platform} To ${new_value}
|
|
|
|
# Remember previous value.
|
|
${result_upper_original_value}= Execute Command ${cpu} GetRegister ${${rd} + 1}
|
|
${rs2_upper_original_value}= Execute Command ${cpu} GetRegister ${${rs2} + 1}
|
|
|
|
# Perform amocas.
|
|
Execute Command ${cpu} Step
|
|
|
|
IF "${rd}" != "0"
|
|
# After amocas, rd register should have the original memory value (before the cas)...
|
|
Amocas.${size} Register ${rd} On ${platform} Should Contain ${ORIGINAL_VALUE_MASKED}
|
|
ELSE IF ("${platform}" == "RV32" and "${size}" == "d") or ("${platform}" == "RV64" and "${size}" == "q")
|
|
# Unless rd is x0, in which case the original memory value is discarded and neither result register is written.
|
|
# Ensure rd+1 isn't written to.
|
|
Register Should Be Equal ${${rd} + 1} ${result_upper_original_value} cpuName=${cpu}
|
|
END
|
|
# and the others should remain unchanged
|
|
IF "${rs2}" != "0"
|
|
Amocas.${size} Register ${rs2} On ${platform} Should Contain ${new_value}
|
|
ELSE IF ("${platform}" == "RV32" and "${size}" == "d") or ("${platform}" == "RV64" and "${size}" == "q")
|
|
# Unless rs2 is x0, in which case rs2+1 is interpreted as 0 no matter its contents.
|
|
# Ensure rs2+1 remains unchanged.
|
|
Register Should Be Equal ${${rs2} + 1} ${rs2_upper_original_value} cpuName=${cpu}
|
|
END
|
|
Register Should Be Equal ${rs1} ${variable_address} cpuName=${cpu}
|
|
|
|
IF "${should}" == "Should"
|
|
# Now value in memory should have been set.
|
|
Amocas.${size} Memory Location ${variable_address} Should Now Be Set To ${new_value}
|
|
ELSE
|
|
# Value in memory should remain unchanged.
|
|
Amocas.${size} Memory Location ${variable_address} Should Now Be Set To ${ORIGINAL_VALUE_MASKED}
|
|
END
|
|
|
|
*** Test Cases ***
|
|
# w should tests
|
|
Amocas.w On RV64 Should Set Value At Single-Page Memory Location
|
|
Amocas.w On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${expected_32}
|
|
|
|
Amocas.w On RV64 Should Set Value At Page-Spanning Memory Location
|
|
Amocas.w On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_32} If Expecting ${expected_32}
|
|
|
|
Amocas.w On RV64 Should Set Value At MMIO Memory Location
|
|
Amocas.w On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_32} If Expecting ${expected_32}
|
|
|
|
Amocas.w On RV32 Should Set Value At Single-Page Memory Location
|
|
Amocas.w On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${expected_32}
|
|
|
|
# w shouldn't tests
|
|
|
|
Amocas.w On RV64 Shouldn't Set Value At Single-Page Memory Location
|
|
Amocas.w On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32}
|
|
|
|
Amocas.w On RV64 Shouldn't Set Value At Page-Spanning Memory Location
|
|
Amocas.w On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32}
|
|
|
|
Amocas.w On RV64 Shouldn't Set Value At MMIO Memory Location
|
|
Amocas.w On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32}
|
|
|
|
Amocas.w On RV32 Shouldn't Set Value At Single-Page Memory Location
|
|
Amocas.w On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32}
|
|
|
|
# d should tests
|
|
|
|
Amocas.d On RV64 Should Set Value At Single-Page Memory Location
|
|
Amocas.d On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64}
|
|
|
|
Amocas.d On RV32 Should Set Value At Single-Page Memory Location
|
|
Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64}
|
|
|
|
Amocas.d On RV32 Should Handle Zero Source Register
|
|
# Place value in rs2+1 which should be ignored.
|
|
Execute Command cpu32 SetRegister ${${x0} + 1} ${wrong_expected_32}
|
|
|
|
Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To 0 If Expecting ${expected_64}
|
|
... rs2=${x0}
|
|
|
|
Amocas.d On RV32 Should Handle Zero Destination Register
|
|
# Place value in rd+1 which shouldn't be overwritten.
|
|
Execute Command cpu32 SetRegister ${${x0} + 1} ${wrong_expected_32}
|
|
|
|
Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting 0
|
|
... rd=${x0}
|
|
... original_value_lower=0
|
|
|
|
Amocas.d On RV64 Should Set Value At Page-Spanning Memory Location
|
|
Amocas.d On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_64} If Expecting ${expected_64}
|
|
|
|
Amocas.d On RV64 Should Set Value At MMIO Memory Location
|
|
Amocas.d On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_64} If Expecting ${expected_64}
|
|
|
|
# d shouldn't tests
|
|
|
|
Amocas.d On RV64 Shouldn't Set Value At Single-Page Memory Location
|
|
Amocas.d On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64}
|
|
|
|
Amocas.d On RV32 Shouldn't Set Value At Single-Page Memory Location
|
|
Amocas.d On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64}
|
|
|
|
Amocas.d On RV64 Shouldn't Set Value At Page-Spanning Memory Location
|
|
Amocas.d On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64}
|
|
|
|
Amocas.d On RV64 Shouldn't Set Value At MMIO Memory Location
|
|
Amocas.d On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64}
|
|
|
|
# q should tests
|
|
|
|
Amocas.q On RV64 Should Set Value At Single-Page Memory Location
|
|
Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${expected_128}
|
|
|
|
Amocas.q On RV64 Should Set Value At Page-Spanning Memory Location
|
|
Amocas.q On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_128} If Expecting ${expected_128}
|
|
|
|
Amocas.q On RV64 Should Set Value At MMIO Memory Location
|
|
Amocas.q On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_128} If Expecting ${expected_128}
|
|
|
|
Amocas.q On RV64 Should Handle Zero Source Register
|
|
# Place value in rs2+1 which should be ignored.
|
|
Execute Command cpu SetRegister ${${x0} + 1} ${wrong_expected_32}
|
|
|
|
Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To 0 If Expecting ${expected_128}
|
|
... rs2=${x0}
|
|
|
|
Amocas.q On RV64 Should Handle Zero Destination Register
|
|
# Place value in rd+1 which shouldn't be overwritten.
|
|
Execute Command cpu SetRegister ${${x0} + 1} ${wrong_expected_32}
|
|
|
|
Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting 0
|
|
... rd=${x0}
|
|
... original_value_lower=0
|
|
... original_value_upper=0
|
|
|
|
# q shouldn't tests
|
|
|
|
Amocas.q On RV64 Shouldn't Set Value At Single-Page Memory Location
|
|
Amocas.q On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128}
|
|
|
|
Amocas.q On RV64 Shouldn't Set Value At Page-Spanning Memory Location
|
|
Amocas.q On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128}
|
|
|
|
Amocas.q On RV64 Shouldn't Set Value At MMIO Memory Location
|
|
Amocas.q On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128}
|
|
|
|
# illegal instructions
|
|
|
|
Amocas.d On RV32 Using Odd Registers Should Throw Illegal Instruction
|
|
${odd_rd}= Set Variable ${${a0} + 1}
|
|
${odd_rs2}= Set Variable ${${s2} + 1}
|
|
|
|
Amocas.d On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64}
|
|
... rd=${odd_rd}
|
|
... rs2=${odd_rs2}
|
|
|
|
Amocas.d ${odd_rd} ${odd_rs2} ${a3} On RV32 Should Throw Illegal Instruction
|
|
|
|
Amocas.q On RV64 Using Odd Registers Should Throw Illegal Instruction
|
|
${odd_rd}= Set Variable ${${a0} + 1}
|
|
${odd_rs2}= Set Variable ${${s2} + 1}
|
|
|
|
Amocas.q On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${expected_128}
|
|
... rd=${odd_rd}
|
|
... rs2=${odd_rs2}
|
|
|
|
Amocas.q ${odd_rd} ${odd_rs2} ${a3} On RV64 Should Throw Illegal Instruction
|