lib/std/arch/rv64/atomicTests.rad 4.9 KiB raw
1
//! RV64 A-extension and fence encoding checks.
2
3
use std::testing;
4
use std::lang::alloc;
5
use std::lang::strings;
6
use super::atomics;
7
use super::encode;
8
use super::decode;
9
use super::asm;
10
11
/// Assembler workspace for individual atomic instruction fixtures.
12
static MEMORY: [u8; 65536] = [0; 65536];
13
/// Interned fixture names.
14
unsafe static STRINGS: strings::Pool = strings::Pool { table: undefined, count: 0 };
15
16
/// Output storage for one assembled instruction.
17
static WORDS: [u32; 1] = [0; 1];
18
19
/// Exact unordered word encodings for a0, a1, and a2 operands.
20
@test fn encodings() throws (testing::TestError) {
21
    let operations: [u32; 11] = [0, 1, 2, 3, 4, 8, 12, 16, 20, 24, 28];
22
    let words: [u32; 11] = [
23
        0x00c5a52f, 0x08c5a52f, 0x1005a52f, 0x18c5a52f, 0x20c5a52f,
24
        0x40c5a52f, 0x60c5a52f, 0x80c5a52f, 0xa0c5a52f, 0xc0c5a52f, 0xe0c5a52f,
25
    ];
26
    for operation, i in &operations[..] {
27
        for wide in 0..2 {
28
            for order in 0..4 {
29
                let item = atomics::Instruction {
30
                    format: atomics::Format { operation, width: 2 + wide, order },
31
                    rd: super::A0, rs1: super::A1, rs2: super::ZERO if operation == 2 else super::A2,
32
                };
33
                let word = words[i] | (wide << 12) | (order << 25);
34
                try testing::expect(atomics::encode(item) == word);
35
                let decoded = atomics::decode(word) else { throw testing::TestError::Failed; };
36
                try testing::expect(decoded == item);
37
                let case decode::Instr::Atomic(instruction) = decode::decode(word) else { throw testing::TestError::Failed; };
38
                try testing::expect(instruction == item);
39
            }
40
        }
41
    }
42
}
43
44
/// Reject reserved opcodes, widths, LR sources, and malformed suffixes.
45
@test fn invalid() throws (testing::TestError) {
46
    for word in &[0x2805a52f, 0x00c5852f, 0x10c5a52f, 0x00c5a513] {
47
        try testing::expect(atomics::decode(word) == nil);
48
    }
49
    for name in &["lr", "lr.q", "lr.w.aq.rl", "sc.d.rl.aq", "amoswap.d.bad", "amoadd.wextra"] {
50
        try testing::expect(atomics::parse(name) == nil);
51
    }
52
    let format = atomics::parse("amoswap.d.aqrl") else { throw testing::TestError::Failed; };
53
    try testing::expect(format.operation == 1 and format.width == 3 and format.order == 3);
54
}
55
56
/// Assemble one instruction and return its exact word.
57
unsafe fn assemble(source: *[u8]) -> u32 throws (testing::TestError) {
58
    let mut arena = alloc::new(&mut MEMORY[..]);
59
    let words = &mut WORDS[..];
60
    let data: *mut [u8] = &mut [];
61
    let result = try asm::assemble(asm::scanner::SourceKind::String, source,
62
        &mut words[..], &mut data[..], &mut arena, &mut STRINGS, 0)
63
        catch { throw testing::TestError::Failed; };
64
    try testing::expect(result.text.len == 1);
65
    return result.text[0];
66
}
67
68
/// Check instruction suffix scanning and assembler operand order.
69
@test unsafe fn assembly() throws (testing::TestError) {
70
    try testing::expect((try assemble("amoadd.d.aqrl %a0 %a2 (%a1);")) == 0x06c5b52f);
71
    try testing::expect((try assemble("amoswap.w.aq %a0 %a2 0(%a1);")) == 0x0cc5a52f);
72
    try testing::expect((try assemble("lr.d.aq %a0 (%a1);")) == 0x1405b52f);
73
    try testing::expect((try assemble("sc.w.rl %a0 %a2 (%a1);")) == 0x1ac5a52f);
74
    try testing::expect((try assemble("fence.i;")) == 0x0000100f);
75
    try testing::expect((try assemble("fence iorw iorw;")) == 0x0ff0000f);
76
    try testing::expect((try assemble("fence r rw;")) == 0x0230000f);
77
    try testing::expect((try assemble("fence rw w;")) == 0x0310000f);
78
    try testing::expect((try assemble("fence 0 0;")) == 0x0000000f);
79
}
80
81
/// Decode fence classes and local instruction synchronization.
82
@test fn fences() throws (testing::TestError) {
83
    try testing::expect(encode::fenceI() == 0x0000100f);
84
    try testing::expect(decode::decode(encode::fenceI()) == decode::Instr::FenceI);
85
    let case decode::Instr::Fence { predecessor, successor } = decode::decode(encode::fenceOrder(15, 15))
86
        else { throw testing::TestError::Failed; };
87
    try testing::expect(predecessor == 15 and successor == 15);
88
    let case decode::Instr::Unknown { .. } = decode::decode(0x0000200f)
89
        else { throw testing::TestError::Failed; };
90
}
91
92
/// Reject invalid atomic operands and fence access classes.
93
@test unsafe fn invalidAssembly() throws (testing::TestError) {
94
    for source in &[
95
        "lr.w %a0 %a2 (%a1);", "sc.d %a0 %a2 8(%a1);",
96
        "amoadd.d.aq.aq %a0 %a2 (%a1);", "fence rr rw;", "fence rx rw;",
97
        "fence 1 rw;", "fence.i %a0;",
98
    ] {
99
        let mut arena = alloc::new(&mut MEMORY[..]);
100
        let words = &mut WORDS[..];
101
        let data: *mut [u8] = &mut [];
102
        let mut rejected = false;
103
        try asm::assemble(asm::scanner::SourceKind::String, source,
104
            &mut words[..], &mut data[..], &mut arena, &mut STRINGS, 0) catch {
105
            set rejected = true;
106
        };
107
        try testing::expect(rejected);
108
    }
109
}