lib/std/arch/rv64/atomics.rad 3.4 KiB raw
1
//! RV64 atomic instruction fields and canonical assembly names.
2
3
use std::mem;
4
use std::lang::gen;
5
6
/// Atomic operation, width, and ordering fields.
7
export record Format: Copy {
8
    /// Five-bit operation code from the A extension.
9
    operation: u32,
10
    /// Memory width encoding: 2 for a word, 3 for a doubleword.
11
    width: u32,
12
    /// Ordering bits: 2 for acquire, 1 for release, 3 for both.
13
    order: u32,
14
}
15
16
/// Decoded atomic instruction operands.
17
export record Instruction: Copy {
18
    /// Operation and ordering fields.
19
    format: Format,
20
    /// Destination register.
21
    rd: gen::Reg,
22
    /// Address register.
23
    rs1: gen::Reg,
24
    /// Source value; zero for load-reserved.
25
    rs2: gen::Reg,
26
}
27
28
/// An architectural operation and its mnemonic stem.
29
record Operation: Copy {
30
    /// Mnemonic without width or ordering suffixes.
31
    name: *[u8],
32
    /// Five-bit instruction field.
33
    code: u32,
34
}
35
36
/// Operations shared by the 32-bit and 64-bit forms.
37
constant OPERATIONS: [Operation; 11] = [
38
    { name: "amoadd", code: 0 }, { name: "amoswap", code: 1 },
39
    { name: "lr", code: 2 }, { name: "sc", code: 3 },
40
    { name: "amoxor", code: 4 }, { name: "amoor", code: 8 },
41
    { name: "amoand", code: 12 }, { name: "amomin", code: 16 },
42
    { name: "amomax", code: 20 }, { name: "amominu", code: 24 },
43
    { name: "amomaxu", code: 28 },
44
];
45
46
/// Look up an operation's canonical mnemonic stem.
47
export fn name(code: u32) -> ?*[u8] {
48
    for operation in &OPERATIONS[..] { if operation.code == code { return operation.name; } }
49
    return nil;
50
}
51
52
/// Parse an atomic mnemonic with mandatory width and optional ordering suffix.
53
export fn parse(text: *[u8]) -> ?Format {
54
    for operation in &OPERATIONS[..] {
55
        let n = operation.name.len;
56
        if text.len < n + 2 or not mem::eq(&text[..n], operation.name) or text[n] <> '.' { continue; }
57
        let mut width: u32 = 2;
58
        if text[n + 1] == 'd' { set width = 3; }
59
        else if text[n + 1] <> 'w' { return nil; }
60
        let suffix = &text[n + 2..];
61
        let mut order: u32 = 0;
62
        if mem::eq(suffix, ".aq") { set order = 2; }
63
        else if mem::eq(suffix, ".rl") { set order = 1; }
64
        else if mem::eq(suffix, ".aqrl") { set order = 3; }
65
        else if suffix.len <> 0 { return nil; }
66
        return Format { operation: operation.code, width, order };
67
    }
68
    return nil;
69
}
70
71
/// Encode a validated atomic operation and register operands.
72
export fn encode(instruction: Instruction) -> u32 {
73
    let format = instruction.format;
74
    assert name(format.operation) <> nil and (format.width == 2 or format.width == 3) and format.order <= 3;
75
    assert format.operation <> 2 or instruction.rs2 == super::ZERO;
76
    return 0x2f | (*instruction.rd as u32 << 7) | (format.width << 12)
77
        | (*instruction.rs1 as u32 << 15) | (*instruction.rs2 as u32 << 20)
78
        | (format.order << 25) | (format.operation << 27);
79
}
80
81
/// Decode a supported atomic word and reject reserved width and LR fields.
82
export fn decode(word: u32) -> ?Instruction {
83
    let operation = word >> 27;
84
    let width = (word >> 12) & 7;
85
    let rs2 = super::reg(((word >> 20) & 31) as u8);
86
    if (word & 127) <> 0x2f or name(operation) == nil or (width <> 2 and width <> 3) { return nil; }
87
    if operation == 2 and rs2 <> super::ZERO { return nil; }
88
    return Instruction {
89
        format: Format { operation, width, order: (word >> 25) & 3 },
90
        rd: super::reg(((word >> 7) & 31) as u8), rs1: super::reg(((word >> 15) & 31) as u8), rs2,
91
    };
92
}