lib/std/arch/rv64/atomics.rad 3.6 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[..] {
49
        if operation.code == code {
50
            return operation.name;
51
        }
52
    }
53
    return nil;
54
}
55
56
/// Parse an atomic mnemonic with mandatory width and optional ordering suffix.
57
export fn parse(text: *[u8]) -> ?Format {
58
    for operation in &OPERATIONS[..] {
59
        let n = operation.name.len;
60
        if text.len < n + 2 or not mem::eq(&text[..n], operation.name) or text[n] <> '.' {
61
            continue;
62
        }
63
        let mut width: u32 = 2;
64
        if text[n + 1] == 'd' {
65
            set width = 3;
66
        }
67
        else if text[n + 1] <> 'w' {
68
            return nil;
69
        }
70
        let suffix = &text[n + 2..];
71
        let mut order: u32 = 0;
72
        if mem::eq(suffix, ".aq") {
73
            set order = 2;
74
        }
75
        else if mem::eq(suffix, ".rl") {
76
            set order = 1;
77
        }
78
        else if mem::eq(suffix, ".aqrl") {
79
            set order = 3;
80
        }
81
        else if suffix.len <> 0 {
82
            return nil;
83
        }
84
        return Format { operation: operation.code, width, order };
85
    }
86
    return nil;
87
}
88
89
/// Encode a validated atomic operation and register operands.
90
export fn encode(instruction: Instruction) -> u32 {
91
    let format = instruction.format;
92
    assert name(format.operation) <> nil and (format.width == 2 or format.width == 3) and format.order <= 3;
93
    assert format.operation <> 2 or instruction.rs2 == super::ZERO;
94
    return 0x2f | (*instruction.rd as u32 << 7) | (format.width << 12)
95
        | (*instruction.rs1 as u32 << 15) | (*instruction.rs2 as u32 << 20)
96
        | (format.order << 25) | (format.operation << 27);
97
}
98
99
/// Decode a supported atomic word and reject reserved width and LR fields.
100
export fn decode(word: u32) -> ?Instruction {
101
    let operation = word >> 27;
102
    let width = (word >> 12) & 7;
103
    let rs2 = super::reg(((word >> 20) & 31) as u8);
104
    if (word & 127) <> 0x2f or name(operation) == nil or (width <> 2 and width <> 3) {
105
        return nil;
106
    }
107
    if operation == 2 and rs2 <> super::ZERO {
108
        return nil;
109
    }
110
    return Instruction {
111
        format: Format { operation, width, order: (word >> 25) & 3 },
112
        rd: super::reg(((word >> 7) & 31) as u8), rs1: super::reg(((word >> 15) & 31) as u8), rs2,
113
    };
114
}