compiler/
kernel/
lib/
examples/
std/
arch/
rv64/
asm/
image/
shared/
asm.rad
24.0 KiB
atomicTests.rad
4.9 KiB
atomics.rad
3.4 KiB
bounds.rad
8.5 KiB
decode.rad
15.2 KiB
emit.rad
30.1 KiB
encode.rad
22.0 KiB
image.rad
4.4 KiB
isel.rad
49.1 KiB
printer.rad
14.1 KiB
shared.rad
15.6 KiB
tests.rad
17.2 KiB
rv64.rad
16.0 KiB
char/
collections/
lang/
sys/
arch.rad
68 B
char.rad
855 B
collections.rad
39 B
fmt.rad
8.3 KiB
intrinsics.rad
467 B
io.rad
1.7 KiB
lang.rad
276 B
mem.rad
2.3 KiB
sys.rad
179 B
testing.rad
2.4 KiB
tests.rad
15.7 KiB
vec.rad
3.2 KiB
std.rad
281 B
scripts/
seed/
sublime/
test/
vim/
.gitignore
336 B
.gitsigners
112 B
CONTRIBUTING
2.1 KiB
LICENSE
1.1 KiB
Makefile
10.2 KiB
README
2.5 KiB
STYLE
2.5 KiB
std.lib
1.5 KiB
std.lib.test
551 B
lib/std/arch/rv64/atomicTests.rad
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 | } |