lib/std/arch/rv64/asm/tests.rad 8.2 KiB raw
1
//! RV64 assembler tests.
2
3
use std::testing;
4
use std::mem;
5
use std::lang::alloc;
6
use std::lang::sexpr;
7
use std::lang::strings;
8
use std::arch::rv64;
9
use std::arch::rv64::encode;
10
use std::arch::rv64::printer;
11
12
use super::scanner;
13
14
static ASM_ARENA_STORAGE: [u8; 65536] = [0; 65536];
15
static ASM_TEXT_STORAGE: [u32; 256] = [0; 256];
16
static ASM_DATA_STORAGE: [u8; 1024] = [0; 1024];
17
unsafe static ASM_STRING_POOL: strings::Pool = strings::Pool { table: undefined, count: 0 };
18
static PRINT_ARENA_STORAGE: [u8; 1024] = [0; 1024];
19
static PRINT_BUFFER: [u8; 128] = [0; 128];
20
21
/// The retired-instruction CSR assembles to its exact architectural encoding.
22
@test unsafe fn retiredCounter() throws (testing::TestError) {
23
    let program = try assembleSource(".text;\ncsrr %a0 instret;\n");
24
    assert program.text.len == 1 and program.text[0] == 0xc0202573;
25
}
26
27
/// Source buffer for comment capacity tests.
28
static SOURCE: [u8; 4096] = [0; 4096];
29
30
/// Long comments consume source space while leaving symbol and fixup demand small.
31
@test unsafe fn commentStorage() throws (testing::TestError) {
32
    let source = &mut SOURCE[..];
33
    for i in 0..source.len { set source[i] = 32; }
34
    set source[0] = '/'; set source[1] = '/';
35
    let text = "\n.text;\nret;\n";
36
    for byte, i in text { set source[source.len - text.len + i] = byte; }
37
    let program = try assembleSource(&SOURCE[..]);
38
    try testing::expect(program.text.len == 1 and program.text[0] == encode::ret());
39
}
40
41
unsafe fn assembleSource(source: *[u8]) -> super::Program throws (testing::TestError) {
42
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
43
    return try super::assemble(
44
        scanner::SourceKind::String,
45
        source,
46
        &mut ASM_TEXT_STORAGE[..],
47
        &mut ASM_DATA_STORAGE[..],
48
        &mut arena,
49
        &mut ASM_STRING_POOL,
50
        rv64::RO_DATA_BASE
51
    ) catch {
52
        throw testing::TestError::Failed;
53
    };
54
}
55
56
unsafe fn expectAssembleFail(source: *[u8]) throws (testing::TestError) {
57
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
58
    try super::assemble(
59
        scanner::SourceKind::String,
60
        source,
61
        &mut ASM_TEXT_STORAGE[..],
62
        &mut ASM_DATA_STORAGE[..],
63
        &mut arena,
64
        &mut ASM_STRING_POOL,
65
        rv64::RO_DATA_BASE
66
    ) catch {
67
        return;
68
    };
69
    throw testing::TestError::Failed;
70
}
71
72
unsafe fn printInstrText(instr: u32) -> *[u8] {
73
    let mut arena = alloc::new(&mut PRINT_ARENA_STORAGE[..]);
74
    let mut pos: u32 = 0;
75
    let mut out = sexpr::Output::Buffer { buf: &mut PRINT_BUFFER[..], pos: &mut pos };
76
    printer::printInstr(&mut out, &mut arena, instr);
77
    return &PRINT_BUFFER[..pos];
78
}
79
80
@test unsafe fn testAssemblePercentPrefixedRegisters() throws (testing::TestError) {
81
    let program = try assembleSource(
82
        ".text;\naddi %a0 %zero 42;\nsd %a0 8(%sp);\n"
83
    );
84
    try testing::expect(program.text.len == 2);
85
    try testing::expect(program.text[0] == encode::addi(rv64::A0, rv64::ZERO, 42));
86
    try testing::expect(program.text[1] == encode::sd(rv64::A0, rv64::SP, 8));
87
}
88
89
@test unsafe fn testAssembleDataAddressUsesRoDataBase() throws (testing::TestError) {
90
    let program = try assembleSource(
91
        ".text;\nla %t0 @value;\n.data;\n.byte 0;\n@value\n.byte 1;\n"
92
    );
93
    try testing::expect(program.text.len == 2);
94
    try testing::expect(program.text[0] == encode::lui(rv64::T0, 0x10));
95
    try testing::expect(program.text[1] == encode::addi(rv64::T0, rv64::T0, 1));
96
}
97
98
@test unsafe fn testAssembleTextAddressUsesPcRelative() throws (testing::TestError) {
99
    let program = try assembleSource(
100
        ".text;\nla %t0 @target;\n@target\nret;\n"
101
    );
102
    try testing::expect(program.text.len == 3);
103
    try testing::expect(program.text[0] == encode::auipc(rv64::T0, 0));
104
    try testing::expect(program.text[1] == encode::addi(rv64::T0, rv64::T0, 8));
105
}
106
107
@test unsafe fn testAssembleQuotedLabelNames() throws (testing::TestError) {
108
    let program = try assembleSource(
109
        ".text;\nj @\"foo.bar.baz\";\n@\"foo.bar.baz\"\nret;\n"
110
    );
111
    try testing::expect(program.text.len == 2);
112
    try testing::expect(program.text[0] == encode::jal(rv64::ZERO, 4));
113
    try testing::expect(program.text[1] == encode::jalr(rv64::ZERO, rv64::RA, 0));
114
}
115
116
@test unsafe fn testAssembleGlobalMarksOnlyDeclaredSymbols() throws (testing::TestError) {
117
    let program = try assembleSource(
118
        ".text;\n.export @exported;\n@local\nret;\n@exported\nret;\n@late\n.export @late;\nret;\n"
119
    );
120
    try testing::expect(program.symbols.len == 3);
121
    try testing::expect(not program.symbols[0].isExported);
122
    try testing::expect(program.symbols[1].isExported);
123
    try testing::expect(program.symbols[2].isExported);
124
}
125
126
@test unsafe fn testAssembleExternalTextFixups() throws (testing::TestError) {
127
    let program = try assembleSource(
128
        ".text;\ntail @\"::default\";\nla %t0 @\"::default\";\n"
129
    );
130
    try testing::expect(program.externalFixups.len == 2);
131
132
    let case super::FixupInfo::Jal { rd, index } = program.externalFixups[0].info else {
133
        throw testing::TestError::Failed;
134
    };
135
    try testing::expect(mem::eq(program.externalFixups[0].symbol, "::default"));
136
    try testing::expect(rd == rv64::ZERO);
137
    try testing::expect(index == 0);
138
139
    let case super::FixupInfo::Addr { rd: addrRd, index: addrIndex } = program.externalFixups[1].info else {
140
        throw testing::TestError::Failed;
141
    };
142
    try testing::expect(mem::eq(program.externalFixups[1].symbol, "::default"));
143
    try testing::expect(addrRd == rv64::T0);
144
    try testing::expect(addrIndex == 1);
145
}
146
147
@test unsafe fn testAssembleInvalidOperandsFail() throws (testing::TestError) {
148
    try expectAssembleFail(
149
        ".text;\nbeq %a0 %a1 @missing;\n"
150
    );
151
    try expectAssembleFail(
152
        ".text;\naddi a0 zero 1;\n"
153
    );
154
    try expectAssembleFail(
155
        ".text;\naddi % a0 %zero 1;\n"
156
    );
157
    try expectAssembleFail(
158
        ".text;\nli %a0 UNKNOWN;\n"
159
    );
160
    try expectAssembleFail(
161
        ".text;\n@start\nj start;\n"
162
    );
163
    try expectAssembleFail(
164
        ".data;\n.dword @missing;\n"
165
    );
166
}
167
168
@test unsafe fn testAssembleInvalidSyntaxFails() throws (testing::TestError) {
169
    try expectAssembleFail(
170
        ".text;\n@dup\n@dup\nret;\n"
171
    );
172
    try expectAssembleFail(
173
        ".text;\naddi %a0, %zero, 1\n"
174
    );
175
    try expectAssembleFail(
176
        ".constant PAGE, 4096;\n"
177
    );
178
    try expectAssembleFail(
179
        ".text;\naddi %a0, %zero, 1;\n"
180
    );
181
    try expectAssembleFail(
182
        ".export @kernel::main, @data::sym;\n"
183
    );
184
}
185
186
@test unsafe fn testAssembleInvalidSectionsFail() throws (testing::TestError) {
187
    try expectAssembleFail(
188
        ".data;\n.dword @target;\n.text;\n@target\nret;\n"
189
    );
190
    try expectAssembleFail(
191
        ".data;\naddi %a0 %zero 1;\n"
192
    );
193
    try expectAssembleFail(
194
        ".text;\n.byte 1;\n"
195
    );
196
    try expectAssembleFail(
197
        ".text;\n.word 1;\n"
198
    );
199
    try expectAssembleFail(
200
        ".text;\n.dword 1;\n"
201
    );
202
    try expectAssembleFail(
203
        ".text;\n.ascii \"x\";\n"
204
    );
205
    try expectAssembleFail(
206
        ".data;\n@value\n.byte 1;\n.text;\nj @value;\n"
207
    );
208
}
209
210
@test unsafe fn testAssembleInvalidDirectivesFail() throws (testing::TestError) {
211
    try expectAssembleFail(
212
        ".data;\n.ascii 'x';\n"
213
    );
214
    try expectAssembleFail(
215
        ".data;\n.byte 1 + 2;\n"
216
    );
217
    try expectAssembleFail(
218
        ".data;\n.byte 256;\n"
219
    );
220
    try expectAssembleFail(
221
        ".data;\n.word 2147483648;\n"
222
    );
223
    try expectAssembleFail(
224
        ".data;\n.space 4294967296;\n"
225
    );
226
    try expectAssembleFail(
227
        ".data;\n.align 3;\n"
228
    );
229
    try expectAssembleFail(
230
        ".text;\n.align 12;\n"
231
    );
232
    try expectAssembleFail(
233
        ".data;\n.align 4294967296;\n"
234
    );
235
}
236
237
@test unsafe fn testAssembleInvalidImmediateRangesFail() throws (testing::TestError) {
238
    try expectAssembleFail(
239
        ".text;\nslli %a0 %a1 64;\n"
240
    );
241
    try expectAssembleFail(
242
        ".text;\nslli %a0 %a1 4294967296;\n"
243
    );
244
    try expectAssembleFail(
245
        ".text;\nslliw %a0 %a1 2147483648;\n"
246
    );
247
    try expectAssembleFail(
248
        ".text;\ncsrsi mstatus 32;\n"
249
    );
250
}
251
252
@test unsafe fn testPrintInstrUsesPercentPrefixedRegisters() throws (testing::TestError) {
253
    let text = printInstrText(encode::addi(rv64::A0, rv64::SP, 42));
254
    try testing::expect(mem::eq(text, "addi    %a0, %sp, 42"));
255
}