Skip to content

Commit 0de3973

Browse files
LibDisassembly: Add RISC-V A extension decoding
1 parent 16a7ece commit 0de3973

File tree

6 files changed

+217
-1
lines changed

6 files changed

+217
-1
lines changed

Userland/Libraries/LibDisassembly/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
set(SOURCES
22
x86/Instruction.cpp
3+
riscv64/A.cpp
34
riscv64/Encoding.cpp
45
riscv64/FD.cpp
56
riscv64/Formatting.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* Copyright (c) 2023, kleines Filmröllchen <[email protected]>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include "A.h"
8+
9+
namespace Disassembly::RISCV64 {
10+
11+
NonnullOwnPtr<InstructionImpl> parse_amo(u32 instruction)
12+
{
13+
auto raw_parts = RawRType::parse(instruction);
14+
auto is_acquire = (raw_parts.funct7 & 0b10) > 0;
15+
auto is_release = (raw_parts.funct7 & 1) > 0;
16+
auto width = MemoryAccessMode::from_funct3(raw_parts.funct3).width;
17+
18+
auto operation = AtomicMemoryOperation::Operation::Swap;
19+
switch (raw_parts.funct7 >> 2) {
20+
case 0b00010:
21+
case 0b00011: {
22+
auto is_sc = (raw_parts.funct7 & (1 << 2)) > 0;
23+
return adopt_own(*new (nothrow) LoadReserveStoreConditional(is_sc ? LoadReserveStoreConditional::Operation::StoreConditional : LoadReserveStoreConditional::Operation::LoadReserve, is_acquire, is_release, width, raw_parts.rs1, raw_parts.rs2, raw_parts.rd));
24+
}
25+
case 0b00001:
26+
operation = AtomicMemoryOperation::Operation::Swap;
27+
break;
28+
case 0b00000:
29+
operation = AtomicMemoryOperation::Operation::Add;
30+
break;
31+
case 0b00100:
32+
operation = AtomicMemoryOperation::Operation::Xor;
33+
break;
34+
case 0b01000:
35+
operation = AtomicMemoryOperation::Operation::Or;
36+
break;
37+
case 0b01100:
38+
operation = AtomicMemoryOperation::Operation::And;
39+
break;
40+
case 0b10000:
41+
operation = AtomicMemoryOperation::Operation::Min;
42+
break;
43+
case 0b10100:
44+
operation = AtomicMemoryOperation::Operation::Max;
45+
break;
46+
case 0b11000:
47+
operation = AtomicMemoryOperation::Operation::MinUnsigned;
48+
break;
49+
case 0b11100:
50+
operation = AtomicMemoryOperation::Operation::MaxUnsigned;
51+
break;
52+
default:
53+
VERIFY_NOT_REACHED();
54+
}
55+
56+
return adopt_own(*new (nothrow) AtomicMemoryOperation(operation, is_acquire, is_release, width, raw_parts.rs1, raw_parts.rs2, raw_parts.rd));
57+
}
58+
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright (c) 2023, kleines Filmröllchen <[email protected]>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#pragma once
8+
9+
#include <LibDisassembly/riscv64/Instruction.h>
10+
11+
// A extension.
12+
namespace Disassembly::RISCV64 {
13+
14+
class AtomicOperation : public RTypeInstruction {
15+
public:
16+
virtual ~AtomicOperation() = default;
17+
bool operator==(AtomicOperation const&) const = default;
18+
19+
AtomicOperation(DataWidth width, bool is_acquire, bool is_release, Register rs1, Register rs2, Register rd)
20+
: RTypeInstruction(rs1, rs2, rd)
21+
, m_width(width)
22+
, m_is_acquire(is_acquire)
23+
, m_is_release(is_release)
24+
{
25+
}
26+
27+
DataWidth width() const { return m_width; }
28+
bool is_acquire() const { return m_is_acquire; }
29+
bool is_release() const { return m_is_release; }
30+
31+
private:
32+
DataWidth m_width;
33+
bool m_is_acquire;
34+
bool m_is_release;
35+
};
36+
37+
class LoadReserveStoreConditional : public AtomicOperation {
38+
public:
39+
enum class Operation : bool {
40+
LoadReserve,
41+
StoreConditional,
42+
};
43+
44+
virtual ~LoadReserveStoreConditional() = default;
45+
virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
46+
virtual String mnemonic() const override;
47+
virtual bool instruction_equals(InstructionImpl const&) const override;
48+
bool operator==(LoadReserveStoreConditional const&) const = default;
49+
50+
LoadReserveStoreConditional(Operation operation, bool is_acquire, bool is_release, DataWidth width, Register rs1, Register rs2, Register rd)
51+
: AtomicOperation(width, is_acquire, is_release, rs1, rs2, rd)
52+
, m_operation(operation)
53+
{
54+
}
55+
56+
private:
57+
Operation m_operation;
58+
};
59+
60+
class AtomicMemoryOperation : public AtomicOperation {
61+
public:
62+
enum class Operation : u8 {
63+
Swap,
64+
Add,
65+
Xor,
66+
And,
67+
Or,
68+
Min,
69+
Max,
70+
MinUnsigned,
71+
MaxUnsigned,
72+
};
73+
74+
virtual ~AtomicMemoryOperation() = default;
75+
virtual String to_string(DisplayStyle display_style, u32 origin, Optional<SymbolProvider const&> symbol_provider) const override;
76+
virtual String mnemonic() const override;
77+
virtual bool instruction_equals(InstructionImpl const&) const override;
78+
bool operator==(AtomicMemoryOperation const&) const = default;
79+
80+
AtomicMemoryOperation(Operation operation, bool is_acquire, bool is_release, DataWidth width, Register rs1, Register rs2, Register rd)
81+
: AtomicOperation(width, is_acquire, is_release, rs1, rs2, rd)
82+
, m_operation(operation)
83+
{
84+
}
85+
86+
private:
87+
Operation m_operation;
88+
};
89+
90+
NonnullOwnPtr<InstructionImpl> parse_amo(u32 instruction);
91+
92+
}

Userland/Libraries/LibDisassembly/riscv64/Formatting.cpp

+21
Original file line numberDiff line numberDiff line change
@@ -352,4 +352,25 @@ String Fence::mnemonic() const
352352
VERIFY_NOT_REACHED();
353353
}
354354

355+
String AtomicMemoryOperation::to_string(DisplayStyle display_style, u32, Optional<SymbolProvider const&>) const
356+
{
357+
return MUST(String::formatted("{:10} {}, {}, {}", mnemonic(), format_register(destination_register(), display_style), format_register(source_register_1(), display_style), format_register(source_register_2(), display_style)));
358+
}
359+
360+
String AtomicMemoryOperation::mnemonic() const
361+
{
362+
return MUST(String::formatted("amo{}.{}{}{}", m_operation, MemoryAccessMode { width(), Signedness::Signed }, is_acquire() ? ".aq"sv : ""sv, is_release() ? ".rl"sv : ""sv));
363+
}
364+
365+
String LoadReserveStoreConditional::to_string(DisplayStyle display_style, u32, Optional<SymbolProvider const&>) const
366+
{
367+
return MUST(String::formatted("{:10} {}, {} ({})", mnemonic(), format_register(destination_register(), display_style), format_register(source_register_2(), display_style), format_register(source_register_1(), display_style)));
368+
}
369+
370+
String LoadReserveStoreConditional::mnemonic() const
371+
{
372+
auto operation = m_operation == Operation::LoadReserve ? "lr"sv : "sc"sv;
373+
return MUST(String::formatted("{}.{}{}{}", operation, MemoryAccessMode { width(), Signedness::Signed }, is_acquire() ? ".aq"sv : ""sv, is_release() ? ".rl"sv : ""sv));
374+
}
375+
355376
}

Userland/Libraries/LibDisassembly/riscv64/Formatting.h

+40
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <AK/Format.h>
1010
#include <AK/String.h>
11+
#include <LibDisassembly/riscv64/A.h>
1112
#include <LibDisassembly/riscv64/Encoding.h>
1213
#include <LibDisassembly/riscv64/FD.h>
1314
#include <LibDisassembly/riscv64/IM.h>
@@ -580,6 +581,45 @@ struct AK::Formatter<Disassembly::RISCV64::MemoryAccessMode> : AK::Formatter<For
580581
}
581582
};
582583

584+
template<>
585+
struct AK::Formatter<Disassembly::RISCV64::AtomicMemoryOperation::Operation> : AK::Formatter<StringView> {
586+
ErrorOr<void> format(FormatBuilder& builder, Disassembly::RISCV64::AtomicMemoryOperation::Operation op)
587+
{
588+
auto op_name = ""sv;
589+
switch (op) {
590+
591+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Swap:
592+
op_name = "swap"sv;
593+
break;
594+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Add:
595+
op_name = "add"sv;
596+
break;
597+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Xor:
598+
op_name = "xor"sv;
599+
break;
600+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::And:
601+
op_name = "and"sv;
602+
break;
603+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Or:
604+
op_name = "or"sv;
605+
break;
606+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Min:
607+
op_name = "min"sv;
608+
break;
609+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::Max:
610+
op_name = "max"sv;
611+
break;
612+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::MinUnsigned:
613+
op_name = "minu"sv;
614+
break;
615+
case Disassembly::RISCV64::AtomicMemoryOperation::Operation::MaxUnsigned:
616+
op_name = "maxu"sv;
617+
break;
618+
}
619+
return AK::Formatter<StringView>::format(builder, op_name);
620+
}
621+
};
622+
583623
template<>
584624
struct AK::Formatter<Disassembly::RISCV64::RoundingMode> : AK::Formatter<StringView> {
585625
ErrorOr<void> format(FormatBuilder& builder, Disassembly::RISCV64::RoundingMode reg)

Userland/Libraries/LibDisassembly/riscv64/Instruction.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
#include "Instruction.h"
8+
#include "A.h"
89
#include "Encoding.h"
910
#include "FD.h"
1011
#include "IM.h"
@@ -116,7 +117,9 @@ bool simple_instruction_equals(InstructionType const& self, InstructionImpl cons
116117
M(CSRRegisterInstruction) \
117118
M(CSRImmediateInstruction) \
118119
M(Fence) \
119-
M(InstructionFetchFence)
120+
M(InstructionFetchFence) \
121+
M(AtomicMemoryOperation) \
122+
M(LoadReserveStoreConditional)
120123

121124
ENUMERATE_INSTRUCTION_IMPLS(MAKE_INSTRUCTION_EQUALS)
122125

0 commit comments

Comments
 (0)