Skip to content

Commit

Permalink
[SC64][SW] sc64deployer: added SDRAM tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Polprzewodnikowy committed May 8, 2024
1 parent a0bd0dd commit 7bc4e6d
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 5 deletions.
37 changes: 37 additions & 0 deletions sw/deployer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions sw/deployer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ image = "0.24.5"
include-flate = { version = "0.2.0", features = ["stable"] }
md5 = "0.7.0"
panic-message = "0.3.0"
rand = "0.8.5"
rust-ini = "0.18.0"
serial2 = "0.2.20"
serialport = "4.3.0"
Expand Down
96 changes: 95 additions & 1 deletion sw/deployer/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ enum Commands {
command: FirmwareCommands,
},

/// Test SC64 hardware
Test,

/// Expose SC64 device over network
Server(ServerArgs),
}
Expand Down Expand Up @@ -333,6 +336,7 @@ fn handle_command(command: &Commands, port: Option<String>, remote: Option<Strin
Commands::Reset => handle_reset_command(connection),
Commands::Set { command } => handle_set_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),
};
match result {
Expand Down Expand Up @@ -781,7 +785,7 @@ fn handle_set_command(connection: Connection, command: &SetCommands) -> Result<(
sc64.set_datetime(datetime)?;
println!(
"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()
);
}

Expand Down Expand Up @@ -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> {
let port = if let Connection::Local(port) = connection {
port
Expand Down
62 changes: 58 additions & 4 deletions sw/deployer/src/sc64/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ pub use self::{
server::ServerEvent,
types::{
BootMode, ButtonMode, ButtonState, CicSeed, DataPacket, DdDiskState, DdDriveType, DdMode,
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, SaveType,
SaveWriteback, Switch, TvType,
DebugPacket, DiagnosticData, DiskPacket, DiskPacketKind, FpgaDebugData, MemoryTestResult,
MemoryTestType, SaveType, SaveWriteback, Switch, TvType,
},
};

Expand All @@ -26,10 +26,12 @@ use self::{
},
};
use chrono::{DateTime, Local};
use rand::Rng;
use std::{
cmp::min,
io::{Read, Seek, Write},
time::Instant,
{cmp::min, time::Duration},
thread::sleep,
time::{Duration, Instant},
};

pub struct SC64 {
Expand Down Expand Up @@ -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(
&mut self,
writer: &mut dyn Write,
Expand Down
27 changes: 27 additions & 0 deletions sw/deployer/src/sc64/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
($sc64:ident, $config:ident) => {{
if let Config::$config(value) = $sc64.command_config_get(ConfigId::$config)? {
Expand Down

0 comments on commit 7bc4e6d

Please sign in to comment.