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