mirror of
https://github.com/Noratrieb/rustv32i.git
synced 2026-01-14 13:25:01 +01:00
92 lines
2.7 KiB
Rust
92 lines
2.7 KiB
Rust
use std::{
|
|
fs::DirEntry,
|
|
io::Write,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use eyre::{Context, bail};
|
|
use rustv32i::emu::{Reg, Status};
|
|
|
|
#[test]
|
|
fn check() -> eyre::Result<()> {
|
|
let tmpdir = tempfile::tempdir().wrap_err("failed to create tempdir")?;
|
|
|
|
let dir =
|
|
Path::new(&std::env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set"))
|
|
.join("tests")
|
|
.join("check");
|
|
let files = std::fs::read_dir(&dir).wrap_err(format!("reading {}", dir.display()))?;
|
|
|
|
for file in files {
|
|
let file = file.wrap_err(format!("reading file in {}", dir.display()))?;
|
|
|
|
let name = file.file_name();
|
|
let name = name.to_str().unwrap();
|
|
if !name.ends_with(".S") {
|
|
continue;
|
|
}
|
|
|
|
test_case(tmpdir.path(), &file, name, "rv32ima")?;
|
|
test_case(tmpdir.path(), &file, name, "rv32imac")?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn test_case(tmpdir: &Path, file: &DirEntry, name: &str, march: &str) -> eyre::Result<()> {
|
|
let name = format!("{name} ({march})");
|
|
write!(std::io::stdout(), "test {name} ...")?;
|
|
std::io::stdout().flush()?;
|
|
|
|
eprintln!("---- START TEST {name} -----");
|
|
|
|
let output = build(&tmpdir, &file.path(), march).wrap_err(format!("building {name}"))?;
|
|
let content =
|
|
std::fs::read(&output).wrap_err(format!("reading output from {}", output.display()))?;
|
|
|
|
let status = rustv32i::execute_linux_elf(
|
|
&content,
|
|
true,
|
|
Box::new(|_, xreg| {
|
|
if xreg[Reg::A7.0 as usize] == u32::MAX {
|
|
if xreg[Reg::A0.0 as usize] == 1 {
|
|
Err(rustv32i::emu::Status::Exit { code: 0 })
|
|
} else {
|
|
Err(rustv32i::emu::Status::Trap("fail"))
|
|
}
|
|
} else {
|
|
Err(rustv32i::emu::Status::Trap("wrong syscall"))
|
|
}
|
|
}),
|
|
)
|
|
.wrap_err(format!("{name} failed"))?;
|
|
|
|
if let Status::Exit { code: 0 } = status {
|
|
writeln!(std::io::stdout(), " ✅")?;
|
|
Ok(())
|
|
} else {
|
|
bail!("{name} returned an error: {status:?}");
|
|
}
|
|
}
|
|
|
|
fn build(tmpdir: &Path, src: &Path, march: &str) -> eyre::Result<PathBuf> {
|
|
let out_path = tmpdir.join(Path::new(src.file_name().unwrap()).with_extension(""));
|
|
|
|
let mut cmd = std::process::Command::new("clang");
|
|
cmd.args(["-target", "riscv32-unknown-none-elf", "-nostdlib"]);
|
|
cmd.arg(format!("-march={march}"));
|
|
cmd.arg(src);
|
|
cmd.arg("-o");
|
|
cmd.arg(&out_path);
|
|
|
|
let output = cmd.output().wrap_err("failed to spawn clang")?;
|
|
if !output.status.success() {
|
|
bail!(
|
|
"failed to compile {}:\n{}",
|
|
src.display(),
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
}
|
|
|
|
Ok(out_path)
|
|
}
|