lib/std/arch/rv64/asm/tests.rad 9.4 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 {
34
        set source[i] = 32;
35
    }
36
    set source[0] = '/'; set source[1] = '/';
37
    let text = "\n.text;\nret;\n";
38
    for byte, i in text {
39
        set source[source.len - text.len + i] = byte;
40
    }
41
    let program = try assembleSource(&SOURCE[..]);
42
    try testing::expect(program.text.len == 1 and program.text[0] == encode::ret());
43
}
44
45
unsafe fn assembleSource(source: *[u8]) -> super::Program throws (testing::TestError) {
46
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
47
    return try super::assemble(
48
        scanner::SourceKind::String,
49
        source,
50
        &mut ASM_TEXT_STORAGE[..],
51
        &mut ASM_DATA_STORAGE[..],
52
        &mut arena,
53
        &mut ASM_STRING_POOL,
54
        rv64::RO_DATA_BASE
55
    ) catch {
56
        throw testing::TestError::Failed;
57
    };
58
}
59
60
unsafe fn expectAssembleFail(source: *[u8]) throws (testing::TestError) {
61
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
62
    try super::assemble(
63
        scanner::SourceKind::String,
64
        source,
65
        &mut ASM_TEXT_STORAGE[..],
66
        &mut ASM_DATA_STORAGE[..],
67
        &mut arena,
68
        &mut ASM_STRING_POOL,
69
        rv64::RO_DATA_BASE
70
    ) catch {
71
        return;
72
    };
73
    throw testing::TestError::Failed;
74
}
75
76
unsafe fn printInstrText(instr: u32) -> *[u8] {
77
    let mut arena = alloc::new(&mut PRINT_ARENA_STORAGE[..]);
78
    let mut pos: u32 = 0;
79
    let mut out = sexpr::Output::Buffer { buf: &mut PRINT_BUFFER[..], pos: &mut pos };
80
    printer::printInstr(&mut out, &mut arena, instr);
81
    return &PRINT_BUFFER[..pos];
82
}
83
84
@test unsafe fn testAssemblePercentPrefixedRegisters() throws (testing::TestError) {
85
    let program = try assembleSource(
86
        ".text;\naddi %a0 %zero 42;\nsd %a0 8(%sp);\n"
87
    );
88
    try testing::expect(program.text.len == 2);
89
    try testing::expect(program.text[0] == encode::addi(rv64::A0, rv64::ZERO, 42));
90
    try testing::expect(program.text[1] == encode::sd(rv64::A0, rv64::SP, 8));
91
}
92
93
@test unsafe fn testAssembleDataAddressUsesRoDataBase() throws (testing::TestError) {
94
    let program = try assembleSource(
95
        ".text;\nla %t0 @value;\n.data;\n.byte 0;\n@value\n.byte 1;\n"
96
    );
97
    try testing::expect(program.text.len == 2);
98
    try testing::expect(program.text[0] == encode::lui(rv64::T0, 0x10));
99
    try testing::expect(program.text[1] == encode::addi(rv64::T0, rv64::T0, 1));
100
}
101
102
@test unsafe fn testAssembleTextAddressUsesPcRelative() throws (testing::TestError) {
103
    let program = try assembleSource(
104
        ".text;\nla %t0 @target;\n@target\nret;\n"
105
    );
106
    try testing::expect(program.text.len == 3);
107
    try testing::expect(program.text[0] == encode::auipc(rv64::T0, 0));
108
    try testing::expect(program.text[1] == encode::addi(rv64::T0, rv64::T0, 8));
109
}
110
111
@test unsafe fn testAssembleQuotedLabelNames() throws (testing::TestError) {
112
    let program = try assembleSource(
113
        ".text;\nj @\"foo.bar.baz\";\n@\"foo.bar.baz\"\nret;\n"
114
    );
115
    try testing::expect(program.text.len == 2);
116
    try testing::expect(program.text[0] == encode::jal(rv64::ZERO, 4));
117
    try testing::expect(program.text[1] == encode::jalr(rv64::ZERO, rv64::RA, 0));
118
}
119
120
@test unsafe fn testAssembleGlobalMarksOnlyDeclaredSymbols() throws (testing::TestError) {
121
    let program = try assembleSource(
122
        ".text;\n.export @exported;\n@local\nret;\n@exported\nret;\n@late\n.export @late;\nret;\n"
123
    );
124
    try testing::expect(program.symbols.len == 3);
125
    try testing::expect(not program.symbols[0].isExported);
126
    try testing::expect(program.symbols[1].isExported);
127
    try testing::expect(program.symbols[2].isExported);
128
}
129
130
@test unsafe fn testAssembleExternalTextFixups() throws (testing::TestError) {
131
    let program = try assembleSource(
132
        ".text;\ntail @\"::default\";\nla %t0 @\"::default\";\n"
133
    );
134
    try testing::expect(program.externalFixups.len == 2);
135
136
    let case super::FixupInfo::Jal { rd, index } = program.externalFixups[0].info else {
137
        throw testing::TestError::Failed;
138
    };
139
    try testing::expect(mem::eq(program.externalFixups[0].symbol, "::default"));
140
    try testing::expect(rd == rv64::ZERO);
141
    try testing::expect(index == 0);
142
143
    let case super::FixupInfo::Addr { rd: addrRd, index: addrIndex } = program.externalFixups[1].info else {
144
        throw testing::TestError::Failed;
145
    };
146
    try testing::expect(mem::eq(program.externalFixups[1].symbol, "::default"));
147
    try testing::expect(addrRd == rv64::T0);
148
    try testing::expect(addrIndex == 1);
149
}
150
151
@test unsafe fn testAssembleTextOverflow() throws (testing::TestError) {
152
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
153
    try super::assemble(
154
        scanner::SourceKind::String,
155
        ".text;\nret;\nret;\n",
156
        &mut ASM_TEXT_STORAGE[..1],
157
        &mut ASM_DATA_STORAGE[..1],
158
        &mut arena,
159
        &mut ASM_STRING_POOL,
160
        rv64::RO_DATA_BASE
161
    ) catch err {
162
        match err {
163
            case super::Error::TextOverflow => return,
164
            else => throw testing::TestError::Failed,
165
        }
166
    };
167
    throw testing::TestError::Failed;
168
}
169
170
@test unsafe fn testAssembleDataOverflow() throws (testing::TestError) {
171
    let mut arena = alloc::new(&mut ASM_ARENA_STORAGE[..]);
172
    try super::assemble(
173
        scanner::SourceKind::String,
174
        ".data;\n.byte 1, 2;\n",
175
        &mut ASM_TEXT_STORAGE[..1],
176
        &mut ASM_DATA_STORAGE[..1],
177
        &mut arena,
178
        &mut ASM_STRING_POOL,
179
        rv64::RO_DATA_BASE
180
    ) catch err {
181
        match err {
182
            case super::Error::DataOverflow => return,
183
            else => throw testing::TestError::Failed,
184
        }
185
    };
186
    throw testing::TestError::Failed;
187
}
188
189
@test unsafe fn testAssembleInvalidOperandsFail() throws (testing::TestError) {
190
    try expectAssembleFail(
191
        ".text;\nbeq %a0 %a1 @missing;\n"
192
    );
193
    try expectAssembleFail(
194
        ".text;\naddi a0 zero 1;\n"
195
    );
196
    try expectAssembleFail(
197
        ".text;\naddi % a0 %zero 1;\n"
198
    );
199
    try expectAssembleFail(
200
        ".text;\nli %a0 UNKNOWN;\n"
201
    );
202
    try expectAssembleFail(
203
        ".text;\n@start\nj start;\n"
204
    );
205
    try expectAssembleFail(
206
        ".data;\n.dword @missing;\n"
207
    );
208
}
209
210
@test unsafe fn testAssembleInvalidSyntaxFails() throws (testing::TestError) {
211
    try expectAssembleFail(
212
        ".text;\n@dup\n@dup\nret;\n"
213
    );
214
    try expectAssembleFail(
215
        ".text;\naddi %a0, %zero, 1\n"
216
    );
217
    try expectAssembleFail(
218
        ".constant PAGE, 4096;\n"
219
    );
220
    try expectAssembleFail(
221
        ".text;\naddi %a0, %zero, 1;\n"
222
    );
223
    try expectAssembleFail(
224
        ".export @kernel::main, @data::sym;\n"
225
    );
226
}
227
228
@test unsafe fn testAssembleInvalidSectionsFail() throws (testing::TestError) {
229
    try expectAssembleFail(
230
        ".data;\n.dword @target;\n.text;\n@target\nret;\n"
231
    );
232
    try expectAssembleFail(
233
        ".data;\naddi %a0 %zero 1;\n"
234
    );
235
    try expectAssembleFail(
236
        ".text;\n.byte 1;\n"
237
    );
238
    try expectAssembleFail(
239
        ".text;\n.word 1;\n"
240
    );
241
    try expectAssembleFail(
242
        ".text;\n.dword 1;\n"
243
    );
244
    try expectAssembleFail(
245
        ".text;\n.ascii \"x\";\n"
246
    );
247
    try expectAssembleFail(
248
        ".data;\n@value\n.byte 1;\n.text;\nj @value;\n"
249
    );
250
}
251
252
@test unsafe fn testAssembleInvalidDirectivesFail() throws (testing::TestError) {
253
    try expectAssembleFail(
254
        ".data;\n.ascii 'x';\n"
255
    );
256
    try expectAssembleFail(
257
        ".data;\n.byte 1 + 2;\n"
258
    );
259
    try expectAssembleFail(
260
        ".data;\n.byte 256;\n"
261
    );
262
    try expectAssembleFail(
263
        ".data;\n.word 2147483648;\n"
264
    );
265
    try expectAssembleFail(
266
        ".data;\n.space 4294967296;\n"
267
    );
268
    try expectAssembleFail(
269
        ".data;\n.align 3;\n"
270
    );
271
    try expectAssembleFail(
272
        ".text;\n.align 12;\n"
273
    );
274
    try expectAssembleFail(
275
        ".data;\n.align 4294967296;\n"
276
    );
277
}
278
279
@test unsafe fn testAssembleInvalidImmediateRangesFail() throws (testing::TestError) {
280
    try expectAssembleFail(
281
        ".text;\nslli %a0 %a1 64;\n"
282
    );
283
    try expectAssembleFail(
284
        ".text;\nslli %a0 %a1 4294967296;\n"
285
    );
286
    try expectAssembleFail(
287
        ".text;\nslliw %a0 %a1 2147483648;\n"
288
    );
289
    try expectAssembleFail(
290
        ".text;\ncsrsi mstatus 32;\n"
291
    );
292
}
293
294
@test unsafe fn testPrintInstrUsesPercentPrefixedRegisters() throws (testing::TestError) {
295
    let text = printInstrText(encode::addi(rv64::A0, rv64::SP, 42));
296
    try testing::expect(mem::eq(text, "addi    %a0, %sp, 42"));
297
}