compiler/
lib/
examples/
std/
arch/
rv64/
asm/
scanner/
emit.rad
8.2 KiB
parser.rad
30.3 KiB
scanner.rad
9.2 KiB
tests.rad
7.3 KiB
asm.rad
23.3 KiB
decode.rad
14.3 KiB
emit.rad
31.8 KiB
encode.rad
21.6 KiB
isel.rad
51.6 KiB
printer.rad
12.8 KiB
tests.rad
17.2 KiB
rv64.rad
14.4 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
4.1 KiB
README
2.5 KiB
STYLE
2.6 KiB
std.lib
1.2 KiB
std.lib.test
347 B
lib/std/arch/rv64/asm/tests.rad
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 | unsafe 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 | unsafe 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 | unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 unsafe 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 | } |