1*** Settings *** 2Test Setup Create Machine 3 4*** Variables *** 5${MEMORY_START} 0x80000000 6${PLATFORM_STRING} SEPARATOR=\n 7... dram: Memory.MappedMemory @ sysbus ${MEMORY_START} { 8... ${SPACE*4}size: 0x80000000 9... } 10... mmio: Memory.ArrayMemory @ sysbus 0x100000000 { 11... ${SPACE*4}size: 0x10000 12... } 13... mtvec: Memory.MappedMemory @ sysbus 0x1000 { size: 0x40000 } 14... 15... cpu: CPU.RiscV64 @ sysbus { 16... ${SPACE*4}cpuType: "rv64gc_zicsr_zifencei_zacas"; 17... ${SPACE*4}hartId: 1; 18... ${SPACE*4}privilegedArchitecture: PrivilegedArchitecture.Priv1_10; 19... ${SPACE*4}timeProvider: empty; 20... ${SPACE*4}CyclesPerInstruction: 8; 21... ${SPACE*4}allowUnalignedAccesses: true 22... } 23... 24... cpu32: CPU.RiscV32 @ sysbus { 25... ${SPACE*4}cpuType: "rv32gc_zicsr_zifencei_zacas"; 26... ${SPACE*4}hartId: 2; 27... ${SPACE*4}privilegedArchitecture: PrivilegedArchitecture.Priv1_10; 28... ${SPACE*4}timeProvider: empty; 29... ${SPACE*4}CyclesPerInstruction: 8; 30... ${SPACE*4}allowUnalignedAccesses: true 31... } 32${PROGRAM_COUNTER} 0x80000000 33${PROGRAM_COUNTER_32} 0x80000100 34${ORDINARY_ADDRESS} 0x80001000 35${MAX_PAGE_SIZE} 0x40000000 # 1 GiB 36${PAGE_SPANNING_ADDRESS} ${{str(${MEMORY_START} + ${MAX_PAGE_SIZE} - 1)}} # str necessary since robot's XML-RPC library doesn't support >32-bit integers 37${MMIO_ADDRESS} 0x0000000100001000 38 39${mtvec} 0x1010 40${illegal_instruction} 0x2 41 42# Registers used 43${x0} 0 44${a0} 10 45${a1} 11 46${a2} 12 47${a3} 13 48${a4} 14 49${s2} 18 50 51# 32-, 64- and 128-bit constants 52${wrong_expected_128} 0x12345678910111213141516171819202 53${wrong_expected_64} 0x1234567891011 54${wrong_expected_32} 0x1234 55${expected_128} 0x2badc00010ffb0ba1afedeadbeefd00d 56${expected_64} 0x1afedeadbeefd00d 57${expected_32} 0xbeefd00d 58${new_128} 0x216b00b5d0d0caca1eeff00dbabedead 59${new_64} 0xbeeff00dbabedead 60${new_32} 0xbeefbabe 61 62*** Keywords *** 63Create Machine 64 Execute Command mach create 65 Execute Command machine LoadPlatformDescriptionFromString """${PLATFORM_STRING}""" 66 Execute Command cpu ExecutionMode SingleStep 67 Execute Command cpu PC ${PROGRAM_COUNTER} 68 Execute Command cpu32 ExecutionMode SingleStep 69 Execute Command cpu32 PC ${PROGRAM_COUNTER} 70 71Get Cpu On ${platform:(RV32|RV64)} 72 IF "${platform}" == "RV32" 73 ${cpu}= Set Variable cpu32 74 ELSE IF "${platform}" == "RV64" 75 ${cpu}= Set Variable cpu 76 END 77 [return] ${cpu} 78 79Amocas.${size:(w|d|q)} ${rd} ${rs2} ${rs1} On ${platform:(RV32|RV64)} Should Throw Illegal Instruction 80 ${cpu}= Get Cpu On ${platform} 81 82 # Should have jumped to mtvec 83 PC Should Be Equal ${mtvec} cpuName=${cpu} 84 85 # The cause should be illegal instruction. 86 ${mcause}= Execute Command ${cpu} MCAUSE 87 Should Be Equal As Numbers ${mcause} ${illegal_instruction} 88 89 # MTVAL should be the opcode that caused the fault. 90 ${mtval}= Execute Command ${cpu} MTVAL 91 ${illegal_amocas_opcode}= Assemble Amocas.${size} ${rd} ${rs2} ${rs1} 92 Should Be Equal As Numbers ${mtval} ${illegal_amocas_opcode} 93 94 # MEPC should point to the illegal instruction. 95 ${mepc}= Execute Command ${cpu} MEPC 96 Should Be Equal As Numbers ${mepc} ${PROGRAM_COUNTER} 97 98Amocas.${size:(w|d|q)} Memory Location ${address} Should Now Be Set To ${value} 99 IF "${size}" == "w" 100 ${current_value}= Execute Command sysbus ReadDoubleWord ${address} 101 ELSE IF "${size}" == "d" 102 ${current_value}= Execute Command sysbus ReadQuadWord ${address} 103 ELSE IF "${size}" == "q" 104 ${current_value_lower}= Execute Command sysbus ReadQuadWord ${address} 105 ${current_value_upper}= Execute Command sysbus ReadQuadWord ${${address} + 8} 106 END 107 108 IF "${size}" == "q" 109 ${new_value_lower}= Set Variable ${{str(int(${value}) & 0xFFFFFFFFFFFFFFFF)}} 110 ${new_value_upper}= Set Variable ${{str((int(${value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}} 111 Should Be Equal As Integers ${current_value_lower} ${new_value_lower} "Memory location lower should now be set to ${new_value_lower}" 112 Should Be Equal As Integers ${current_value_upper} ${new_value_upper} "Memory location upper should now be set to ${new_value_upper}" 113 ELSE 114 Should Be Equal As Integers ${current_value} ${value} "Memory location ${address} should now be set to ${value} but it's ${current_value}" 115 END 116 117Amocas.${size:(w|d|q)} Register ${register} On ${platform:(RV32|RV64)} Should Contain ${expected_value} 118 ${cpu}= Get Cpu On ${platform} 119 120 IF "${platform}" == "RV32" and "${size}" == "d" 121 # str necessary since robot's XML-RPC library doesn't support >32-bit integers 122 ${expected_value_lower}= Set Variable ${{str(int(${expected_value}) & 0xFFFFFFFF)}} 123 ${expected_value_upper}= Set Variable ${{str((int(${expected_value}) >> 32) & 0xFFFFFFFF)}} 124 Register Should Be Equal ${register} ${expected_value_lower} cpuName=${cpu} 125 Register Should Be Equal ${${register} + 1} ${expected_value_upper} cpuName=${cpu} 126 ELSE IF "${platform}" == "RV64" and "${size}" == "q" 127 # str necessary since robot's XML-RPC library doesn't support >32-bit integers 128 ${expected_value_lower}= Set Variable ${{str(int(${expected_value}) & 0xFFFFFFFFFFFFFFFF)}} 129 ${expected_value_upper}= Set Variable ${{str((int(${expected_value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}} 130 Register Should Be Equal ${register} ${expected_value_lower} cpuName=${cpu} 131 Register Should Be Equal ${${register} + 1} ${expected_value_upper} cpuName=${cpu} 132 ELSE 133 Register Should Be Equal ${register} ${expected_value} cpuName=${cpu} 134 END 135 136Amocas.${size:(w|d|q)} Set Register ${register} On ${platform:(RV32|RV64)} To ${value} 137 ${cpu}= Get Cpu On ${platform} 138 139 IF "${register}" == "0" 140 Return From Keyword 141 END 142 143 IF "${platform}" == "RV32" and "${size}" == "d" 144 ${value_lower}= Set Variable ${{${value} & 0xFFFFFFFF}} 145 ${value_upper}= Set Variable ${{(${value} >> 32) & 0xFFFFFFFF}} 146 Execute Command ${cpu} SetRegister ${register} ${value_lower} 147 Execute Command ${cpu} SetRegister ${${register} + 1} ${value_upper} 148 ELSE IF "${platform}" == "RV64" and "${size}" == "q" 149 # str necessary since robot's XML-RPC library doesn't support >32-bit integers 150 ${value_lower}= Set Variable ${{str(int(${value}) & 0xFFFFFFFFFFFFFFFF)}} 151 ${value_upper}= Set Variable ${{str((int(${value}) >> 64) & 0xFFFFFFFFFFFFFFFF)}} 152 Execute Command ${cpu} SetRegister ${register} ${value_lower} 153 Execute Command ${cpu} SetRegister ${${register} + 1} ${value_upper} 154 ELSE 155 Execute Command ${cpu} SetRegister ${register} ${value} 156 END 157 158Assemble Amocas.${size:(w|d|q)} ${rd} ${rs2} ${rs1} 159 # Hand-assembled instructions necessary due to 160 # our version of the LLVM assembler not supporting the Zacas extension. (issue #74345) 161 162 # The machine code for an amocas instruction with its operands and size zeroed out. 163 ${amocas_base}= Set Variable 0b00101_0_0_00000_00000_000_00000_0101111 164 165 # Translate size mnemonic to corresponding bit pattern. 166 IF "${size}" == "w" 167 ${size_bits}= Set Variable 0b010 168 ELSE IF "${size}" == "d" 169 ${size_bits}= Set Variable 0b011 170 ELSE IF "${size}" == "q" 171 ${size_bits}= Set Variable 0b100 172 END 173 174 # Insert size into instruction 175 ${amocas_sized}= Set Variable ${{${amocas_base} | (${size_bits} << 12)}} 176 177 # Insert rd operand 178 ${amocas_sized_rd}= Set Variable ${{${amocas_sized} | (${rd} << 7)}} 179 180 # Insert rs1 operand 181 ${amocas_sized_rd_rs1}= Set Variable ${{${amocas_sized_rd} | (${rs1} << 15)}} 182 183 # Insert rs2 operand 184 ${amocas_complete}= Set Variable ${{${amocas_sized_rd_rs1} | (${rs2} << 20)}} 185 186 [return] ${amocas_complete} 187 188Amocas.${size:(w|d|q)} On ${platform:(RV32|RV64)} ${should:(Should|Shouldn't)} Set Value At ${variable_address} To ${new_value} If Expecting ${expected_value} 189 [Arguments] 190 ... ${rd}=${a0} 191 ... ${rs1}=${a3} 192 ... ${rs2}=${s2} 193 ... ${original_value_upper}=0x2badc00010ffb0ba 194 ... ${original_value_lower}=${expected_64} 195 196 # Place value in memory. 197 Execute Command sysbus WriteQuadWord ${variable_address} ${original_value_lower} 198 Execute Command sysbus WriteQuadWord ${${variable_address} + 8} ${original_value_upper} 199 200 ${cpu}= Get Cpu On ${platform} 201 202 # Construct amocas instruction. 203 ${MACHINE_CODE_AMOCAS}= Assemble Amocas.${size} ${rd} ${rs2} ${rs1} 204 205 IF "${size}" == "w" 206 # str necessary since robot's XML-RPC library doesn't support >32-bit integers 207 ${ORIGINAL_VALUE_MASKED}= Set Variable ${{str(${original_value_lower} & 0xFFFFFFFF)}} 208 ELSE IF "${size}" == "d" 209 ${ORIGINAL_VALUE_MASKED}= Set Variable ${original_value_lower} 210 ELSE IF "${size}" == "q" 211 # str necessary since robot's XML-RPC library doesn't support >32-bit integers 212 ${ORIGINAL_VALUE_MASKED}= Set Variable "${{str((${original_value_upper} << 64) | ${original_value_lower})}}" 213 END 214 215 # Place machine code at PC. 216 Execute Command sysbus WriteDoubleWord ${PROGRAM_COUNTER} ${MACHINE_CODE_AMOCAS} 217 218 # Set operand values. 219 Amocas.${size} Set Register ${rd} On ${platform} To ${expected_value} 220 Amocas.${size} Set Register ${rs1} On ${platform} To ${variable_address} 221 Amocas.${size} Set Register ${rs2} On ${platform} To ${new_value} 222 223 # Remember previous value. 224 ${result_upper_original_value}= Execute Command ${cpu} GetRegister ${${rd} + 1} 225 ${rs2_upper_original_value}= Execute Command ${cpu} GetRegister ${${rs2} + 1} 226 227 # Perform amocas. 228 Execute Command ${cpu} Step 229 230 IF "${rd}" != "0" 231 # After amocas, rd register should have the original memory value (before the cas)... 232 Amocas.${size} Register ${rd} On ${platform} Should Contain ${ORIGINAL_VALUE_MASKED} 233 ELSE IF ("${platform}" == "RV32" and "${size}" == "d") or ("${platform}" == "RV64" and "${size}" == "q") 234 # Unless rd is x0, in which case the original memory value is discarded and neither result register is written. 235 # Ensure rd+1 isn't written to. 236 Register Should Be Equal ${${rd} + 1} ${result_upper_original_value} cpuName=${cpu} 237 END 238 # and the others should remain unchanged 239 IF "${rs2}" != "0" 240 Amocas.${size} Register ${rs2} On ${platform} Should Contain ${new_value} 241 ELSE IF ("${platform}" == "RV32" and "${size}" == "d") or ("${platform}" == "RV64" and "${size}" == "q") 242 # Unless rs2 is x0, in which case rs2+1 is interpreted as 0 no matter its contents. 243 # Ensure rs2+1 remains unchanged. 244 Register Should Be Equal ${${rs2} + 1} ${rs2_upper_original_value} cpuName=${cpu} 245 END 246 Register Should Be Equal ${rs1} ${variable_address} cpuName=${cpu} 247 248 IF "${should}" == "Should" 249 # Now value in memory should have been set. 250 Amocas.${size} Memory Location ${variable_address} Should Now Be Set To ${new_value} 251 ELSE 252 # Value in memory should remain unchanged. 253 Amocas.${size} Memory Location ${variable_address} Should Now Be Set To ${ORIGINAL_VALUE_MASKED} 254 END 255 256*** Test Cases *** 257# w should tests 258Amocas.w On RV64 Should Set Value At Single-Page Memory Location 259 Amocas.w On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${expected_32} 260 261Amocas.w On RV64 Should Set Value At Page-Spanning Memory Location 262 Amocas.w On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_32} If Expecting ${expected_32} 263 264Amocas.w On RV64 Should Set Value At MMIO Memory Location 265 Amocas.w On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_32} If Expecting ${expected_32} 266 267Amocas.w On RV32 Should Set Value At Single-Page Memory Location 268 Amocas.w On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${expected_32} 269 270# w shouldn't tests 271 272Amocas.w On RV64 Shouldn't Set Value At Single-Page Memory Location 273 Amocas.w On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32} 274 275Amocas.w On RV64 Shouldn't Set Value At Page-Spanning Memory Location 276 Amocas.w On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32} 277 278Amocas.w On RV64 Shouldn't Set Value At MMIO Memory Location 279 Amocas.w On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32} 280 281Amocas.w On RV32 Shouldn't Set Value At Single-Page Memory Location 282 Amocas.w On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_32} If Expecting ${wrong_expected_32} 283 284# d should tests 285 286Amocas.d On RV64 Should Set Value At Single-Page Memory Location 287 Amocas.d On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64} 288 289Amocas.d On RV32 Should Set Value At Single-Page Memory Location 290 Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64} 291 292Amocas.d On RV32 Should Handle Zero Source Register 293 # Place value in rs2+1 which should be ignored. 294 Execute Command cpu32 SetRegister ${${x0} + 1} ${wrong_expected_32} 295 296 Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To 0 If Expecting ${expected_64} 297 ... rs2=${x0} 298 299Amocas.d On RV32 Should Handle Zero Destination Register 300 # Place value in rd+1 which shouldn't be overwritten. 301 Execute Command cpu32 SetRegister ${${x0} + 1} ${wrong_expected_32} 302 303 Amocas.d On RV32 Should Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting 0 304 ... rd=${x0} 305 ... original_value_lower=0 306 307Amocas.d On RV64 Should Set Value At Page-Spanning Memory Location 308 Amocas.d On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_64} If Expecting ${expected_64} 309 310Amocas.d On RV64 Should Set Value At MMIO Memory Location 311 Amocas.d On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_64} If Expecting ${expected_64} 312 313# d shouldn't tests 314 315Amocas.d On RV64 Shouldn't Set Value At Single-Page Memory Location 316 Amocas.d On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64} 317 318Amocas.d On RV32 Shouldn't Set Value At Single-Page Memory Location 319 Amocas.d On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64} 320 321Amocas.d On RV64 Shouldn't Set Value At Single-Page Memory Location 322 Amocas.d On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64} 323 324Amocas.d On RV64 Shouldn't Set Value At Single-Page Memory Location 325 Amocas.d On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_64} If Expecting ${wrong_expected_64} 326 327# q should tests 328 329Amocas.q On RV64 Should Set Value At Single-Page Memory Location 330 Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${expected_128} 331 332Amocas.q On RV64 Should Set Value At Page-Spanning Memory Location 333 Amocas.q On RV64 Should Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_128} If Expecting ${expected_128} 334 335Amocas.q On RV64 Should Set Value At MMIO Memory Location 336 Amocas.q On RV64 Should Set Value At ${MMIO_ADDRESS} To ${new_128} If Expecting ${expected_128} 337 338Amocas.q On RV64 Should Handle Zero Source Register 339 # Place value in rs2+1 which should be ignored. 340 Execute Command cpu SetRegister ${${x0} + 1} ${wrong_expected_32} 341 342 Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To 0 If Expecting ${expected_128} 343 ... rs2=${x0} 344 345Amocas.q On RV64 Should Handle Zero Destination Register 346 # Place value in rd+1 which shouldn't be overwritten. 347 Execute Command cpu SetRegister ${${x0} + 1} ${wrong_expected_32} 348 349 Amocas.q On RV64 Should Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting 0 350 ... rd=${x0} 351 ... original_value_lower=0 352 ... original_value_upper=0 353 354# q shouldn't tests 355 356Amocas.q On RV64 Shouldn't Set Value At Single-Page Memory Location 357 Amocas.q On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128} 358 359Amocas.q On RV64 Shouldn't Set Value At Page-Spanning Memory Location 360 Amocas.q On RV64 Shouldn't Set Value At ${PAGE_SPANNING_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128} 361 362Amocas.q On RV64 Shouldn't Set Value At MMIO Memory Location 363 Amocas.q On RV64 Shouldn't Set Value At ${MMIO_ADDRESS} To ${new_128} If Expecting ${wrong_expected_128} 364 365# illegal instructions 366 367Amocas.d On RV32 Using Odd Registers Should Throw Illegal Instruction 368 ${odd_rd}= Set Variable ${${a0} + 1} 369 ${odd_rs2}= Set Variable ${${s2} + 1} 370 371 Amocas.d On RV32 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_64} If Expecting ${expected_64} 372 ... rd=${odd_rd} 373 ... rs2=${odd_rs2} 374 375 Amocas.d ${odd_rd} ${odd_rs2} ${a3} On RV32 Should Throw Illegal Instruction 376 377Amocas.q On RV64 Using Odd Registers Should Throw Illegal Instruction 378 ${odd_rd}= Set Variable ${${a0} + 1} 379 ${odd_rs2}= Set Variable ${${s2} + 1} 380 381 Amocas.q On RV64 Shouldn't Set Value At ${ORDINARY_ADDRESS} To ${new_128} If Expecting ${expected_128} 382 ... rd=${odd_rd} 383 ... rs2=${odd_rs2} 384 385 Amocas.q ${odd_rd} ${odd_rs2} ${a3} On RV64 Should Throw Illegal Instruction 386