mirror of
https://github.com/Polprzewodnikowy/SummerCart64.git
synced 2024-11-21 21:49:15 +01:00
[SC64][SW] sc64deployer: added SDRAM tests
This commit is contained in:
parent
a0bd0ddd98
commit
7bc4e6d180
37
sw/deployer/Cargo.lock
generated
37
sw/deployer/Cargo.lock
generated
@ -696,6 +696,12 @@ dependencies = [
|
|||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.20+deprecated"
|
version = "0.5.20+deprecated"
|
||||||
@ -729,6 +735,36 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.8.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -810,6 +846,7 @@ dependencies = [
|
|||||||
"include-flate",
|
"include-flate",
|
||||||
"md5",
|
"md5",
|
||||||
"panic-message",
|
"panic-message",
|
||||||
|
"rand",
|
||||||
"rust-ini",
|
"rust-ini",
|
||||||
"serial2",
|
"serial2",
|
||||||
"serialport",
|
"serialport",
|
||||||
|
@ -19,6 +19,7 @@ image = "0.24.5"
|
|||||||
include-flate = { version = "0.2.0", features = ["stable"] }
|
include-flate = { version = "0.2.0", features = ["stable"] }
|
||||||
md5 = "0.7.0"
|
md5 = "0.7.0"
|
||||||
panic-message = "0.3.0"
|
panic-message = "0.3.0"
|
||||||
|
rand = "0.8.5"
|
||||||
rust-ini = "0.18.0"
|
rust-ini = "0.18.0"
|
||||||
serial2 = "0.2.20"
|
serial2 = "0.2.20"
|
||||||
serialport = "4.3.0"
|
serialport = "4.3.0"
|
||||||
|
@ -75,6 +75,9 @@ enum Commands {
|
|||||||
command: FirmwareCommands,
|
command: FirmwareCommands,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Test SC64 hardware
|
||||||
|
Test,
|
||||||
|
|
||||||
/// Expose SC64 device over network
|
/// Expose SC64 device over network
|
||||||
Server(ServerArgs),
|
Server(ServerArgs),
|
||||||
}
|
}
|
||||||
@ -333,6 +336,7 @@ fn handle_command(command: &Commands, port: Option<String>, remote: Option<Strin
|
|||||||
Commands::Reset => handle_reset_command(connection),
|
Commands::Reset => handle_reset_command(connection),
|
||||||
Commands::Set { command } => handle_set_command(connection, command),
|
Commands::Set { command } => handle_set_command(connection, command),
|
||||||
Commands::Firmware { command } => handle_firmware_command(connection, command),
|
Commands::Firmware { command } => handle_firmware_command(connection, command),
|
||||||
|
Commands::Test => handle_test_command(connection),
|
||||||
Commands::Server(args) => handle_server_command(connection, args),
|
Commands::Server(args) => handle_server_command(connection, args),
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
@ -781,7 +785,7 @@ fn handle_set_command(connection: Connection, command: &SetCommands) -> Result<(
|
|||||||
sc64.set_datetime(datetime)?;
|
sc64.set_datetime(datetime)?;
|
||||||
println!(
|
println!(
|
||||||
"SC64 RTC datetime synchronized to: {}",
|
"SC64 RTC datetime synchronized to: {}",
|
||||||
datetime.format("%Y-%m-%d %H:%M:%S %Z").to_string().green()
|
datetime.format("%Y-%m-%d %H:%M:%S").to_string().green()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,6 +881,96 @@ fn handle_firmware_command(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_test_command(connection: Connection) -> Result<(), sc64::Error> {
|
||||||
|
let mut sc64 = init_sc64(connection, false)?;
|
||||||
|
|
||||||
|
println!("{}: SDRAM", "[SC64 Tests]".bold());
|
||||||
|
|
||||||
|
let sdram_tests = [
|
||||||
|
(sc64::MemoryTestType::OwnAddress, None),
|
||||||
|
(sc64::MemoryTestType::AllZeros, None),
|
||||||
|
(sc64::MemoryTestType::AllOnes, None),
|
||||||
|
(sc64::MemoryTestType::Random, None),
|
||||||
|
(sc64::MemoryTestType::Random, None),
|
||||||
|
(sc64::MemoryTestType::Random, None),
|
||||||
|
(sc64::MemoryTestType::AllZeros, Some(60)),
|
||||||
|
(sc64::MemoryTestType::AllOnes, Some(60)),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00010001), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFFEFFFE), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00020002), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFFDFFFD), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00040004), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFFBFFFB), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00080008), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFF7FFF7), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00100010), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFEFFFEF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00200020), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFDFFFDF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00400040), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFFBFFFBF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x00800080), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFF7FFF7F), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x01000100), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFEFFFEFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x02000200), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFDFFFDFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x04000400), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xFBFFFBFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x08000800), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xF7FFF7FF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x10001000), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xEFFFEFFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x20002000), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xDFFFDFFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x40004000), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0xBFFFBFFF), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x80008000), None),
|
||||||
|
(sc64::MemoryTestType::Pattern(0x7FFF7FFF), None),
|
||||||
|
(sc64::MemoryTestType::AllZeros, Some(300)),
|
||||||
|
(sc64::MemoryTestType::AllOnes, Some(300)),
|
||||||
|
];
|
||||||
|
let sdram_tests_count = sdram_tests.len();
|
||||||
|
|
||||||
|
let mut sdram_tests_failed = false;
|
||||||
|
|
||||||
|
for (i, (test_type, fade)) in sdram_tests.into_iter().enumerate() {
|
||||||
|
let fadeout_text = if let Some(fade) = fade {
|
||||||
|
format!(", fadeout {fade} seconds")
|
||||||
|
} else {
|
||||||
|
"".to_string()
|
||||||
|
};
|
||||||
|
print!(
|
||||||
|
" ({} / {sdram_tests_count}) Testing {test_type}{fadeout_text}... ",
|
||||||
|
i + 1
|
||||||
|
);
|
||||||
|
stdout().flush().unwrap();
|
||||||
|
|
||||||
|
let result = sc64.test_sdram(test_type, fade)?;
|
||||||
|
|
||||||
|
if let Some((address, (written, read))) = result.first_error {
|
||||||
|
sdram_tests_failed = true;
|
||||||
|
println!("{}", "error!".bright_red());
|
||||||
|
println!(" Found a mismatch at address 0x{address:08X}",);
|
||||||
|
println!(" 0x{written:08X} (W) != 0x{read:08X} (R)");
|
||||||
|
println!(" Total errors found: {}", result.all_errors.len());
|
||||||
|
} else {
|
||||||
|
println!("{}", "ok".bright_green());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if sdram_tests_failed {
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
"Some SDRAM tests failed, SDRAM chip might be defective".bright_red()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("{}", "All SDRAM tests passed without error".bright_green());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<(), sc64::Error> {
|
fn handle_server_command(connection: Connection, args: &ServerArgs) -> Result<(), sc64::Error> {
|
||||||
let port = if let Connection::Local(port) = connection {
|
let port = if let Connection::Local(port) = connection {
|
||||||
port
|
port
|
||||||
|
@ -12,8 +12,8 @@ pub use self::{
|
|||||||
server::ServerEvent,
|
server::ServerEvent,
|
||||||
types::{
|
types::{
|
||||||
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
|
||||||
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
|
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, MemoryTestResult,
|
||||||
SaveWriteback, Switch, TvType,
|
MemoryTestType, SaveType, SaveWriteback, Switch, TvType,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -26,10 +26,12 @@ use self::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
|
use rand::Rng;
|
||||||
use std::{
|
use std::{
|
||||||
|
cmp::min,
|
||||||
io::{Read, Seek, Write},
|
io::{Read, Seek, Write},
|
||||||
time::Instant,
|
thread::sleep,
|
||||||
{cmp::min, time::Duration},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SC64 {
|
pub struct SC64 {
|
||||||
@ -748,6 +750,58 @@ impl SC64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn test_sdram(
|
||||||
|
&mut self,
|
||||||
|
test_type: MemoryTestType,
|
||||||
|
fade: Option<u64>,
|
||||||
|
) -> Result<MemoryTestResult, Error> {
|
||||||
|
let item_size = std::mem::size_of::<u32>();
|
||||||
|
let mut test_data = vec![0u32; SDRAM_LENGTH / item_size];
|
||||||
|
|
||||||
|
match test_type {
|
||||||
|
MemoryTestType::OwnAddress => {
|
||||||
|
for (index, item) in test_data.iter_mut().enumerate() {
|
||||||
|
*item = (index * item_size) as u32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MemoryTestType::AllZeros => test_data.fill(0x00000000u32),
|
||||||
|
MemoryTestType::AllOnes => test_data.fill(0xFFFFFFFFu32),
|
||||||
|
MemoryTestType::Pattern(pattern) => test_data.fill(pattern),
|
||||||
|
MemoryTestType::Random => rand::thread_rng().fill(&mut test_data[..]),
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_test_data: Vec<u8> = test_data.iter().flat_map(|v| v.to_be_bytes()).collect();
|
||||||
|
self.command_memory_write(SDRAM_ADDRESS, &raw_test_data)?;
|
||||||
|
|
||||||
|
if let Some(fade) = fade {
|
||||||
|
sleep(Duration::from_secs(fade));
|
||||||
|
}
|
||||||
|
|
||||||
|
let raw_check_data = self.command_memory_read(SDRAM_ADDRESS, SDRAM_LENGTH)?;
|
||||||
|
let check_data = raw_check_data
|
||||||
|
.chunks(4)
|
||||||
|
.map(|a| u32::from_be_bytes(a[0..4].try_into().unwrap()));
|
||||||
|
|
||||||
|
let all_errors: Vec<(usize, (u32, u32))> = test_data
|
||||||
|
.into_iter()
|
||||||
|
.zip(check_data)
|
||||||
|
.enumerate()
|
||||||
|
.filter(|(_, (a, b))| a != b)
|
||||||
|
.map(|(i, (a, b))| (i * item_size, (a, b)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let first_error = if all_errors.len() > 0 {
|
||||||
|
Some(all_errors.get(0).copied().unwrap())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(MemoryTestResult {
|
||||||
|
first_error,
|
||||||
|
all_errors,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn memory_read_chunked(
|
fn memory_read_chunked(
|
||||||
&mut self,
|
&mut self,
|
||||||
writer: &mut dyn Write,
|
writer: &mut dyn Write,
|
||||||
|
@ -983,6 +983,33 @@ impl Display for DiagnosticData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum MemoryTestType {
|
||||||
|
OwnAddress,
|
||||||
|
AllZeros,
|
||||||
|
AllOnes,
|
||||||
|
Pattern(u32),
|
||||||
|
Random,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MemoryTestResult {
|
||||||
|
pub first_error: Option<(usize, (u32, u32))>,
|
||||||
|
pub all_errors: Vec<(usize, (u32, u32))>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MemoryTestType {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
MemoryTestType::OwnAddress => f.write_str("Own address"),
|
||||||
|
MemoryTestType::AllZeros => f.write_str("All zeros"),
|
||||||
|
MemoryTestType::AllOnes => f.write_str("All ones"),
|
||||||
|
MemoryTestType::Random => f.write_str("Random"),
|
||||||
|
MemoryTestType::Pattern(pattern) => {
|
||||||
|
f.write_fmt(format_args!("Pattern 0x{pattern:08X}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! get_config {
|
macro_rules! get_config {
|
||||||
($sc64:ident, $config:ident) => {{
|
($sc64:ident, $config:ident) => {{
|
||||||
if let Config::$config(value) = $sc64.command_config_get(ConfigId::$config)? {
|
if let Config::$config(value) = $sc64.command_config_get(ConfigId::$config)? {
|
||||||
|
Loading…
Reference in New Issue
Block a user