From 39bef8f86618b72721fe802ff64f6efeacfd0a19 Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sun, 19 Jun 2022 12:17:34 +0100 Subject: [PATCH 1/3] Add some basic agbabi tests for memcpy --- agb/src/agbabi/mod.rs | 65 +++++++++++++++++++++++++++++++++++++++++++ agb/src/lib.rs | 1 + 2 files changed, 66 insertions(+) create mode 100644 agb/src/agbabi/mod.rs diff --git a/agb/src/agbabi/mod.rs b/agb/src/agbabi/mod.rs new file mode 100644 index 00000000..45d6d711 --- /dev/null +++ b/agb/src/agbabi/mod.rs @@ -0,0 +1,65 @@ +#[cfg(test)] +mod test { + mod memcpy { + use alloc::vec; + + use crate::Gba; + + extern "C" { + fn __agbabi_memcpy(dest: *mut u8, src: *const u8, n: usize); + fn __aeabi_memcpy4(dest: *mut u32, src: *const u32, n: usize); + } + + #[test_case] + fn test_memcpy4_with_different_sizes(_gba: &mut Gba) { + let mut input = vec![0u32; 70]; + let mut output = vec![0u32; 70]; + + for size in 0..68 { + for (i, value) in input.iter_mut().enumerate() { + *value = i as u32 * 6; + } + + output.fill(0); + + unsafe { + __aeabi_memcpy4(output.as_mut_ptr(), input.as_ptr(), size * 4); + } + + for i in 0..size { + assert_eq!(input[i], output[i], "Failed with size = {size} at i = {i}"); + } + + for (i, value) in output.iter().enumerate().skip(size) { + assert_eq!(*value, 0, "overrun with size = {size} at i = {i}"); + } + } + } + + #[test_case] + fn test_memcpy_bytes_with_different_sizes(_gba: &mut Gba) { + let mut input = vec![0u8; 70]; + let mut output = vec![0u8; 70]; + + for size in 0..68 { + for (i, value) in input.iter_mut().enumerate() { + *value = i as u8 * 6; + } + + output.fill(0); + + unsafe { + __agbabi_memcpy(output.as_mut_ptr(), input.as_ptr(), size); + } + + for i in 0..size { + assert_eq!(input[i], output[i], "Failed with size = {size} at i = {i}"); + } + + for (i, value) in output.iter().enumerate().skip(size) { + assert_eq!(*value, 0, "overrun with size = {size} at i = {i}"); + } + } + } + } +} diff --git a/agb/src/lib.rs b/agb/src/lib.rs index 1ac38a4d..a45d570c 100644 --- a/agb/src/lib.rs +++ b/agb/src/lib.rs @@ -157,6 +157,7 @@ pub use agb_sound_converter::include_wav; extern crate alloc; mod agb_alloc; +mod agbabi; mod bitarray; /// Implements everything relating to things that are displayed on screen. pub mod display; From a7d52bbed039f928cece4ef2106e89f13f51646b Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sun, 19 Jun 2022 12:24:55 +0100 Subject: [PATCH 2/3] Add offset tests and failing test for both offetted by 1 byte --- agb/src/agbabi/mod.rs | 90 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/agb/src/agbabi/mod.rs b/agb/src/agbabi/mod.rs index 45d6d711..65f74c4f 100644 --- a/agb/src/agbabi/mod.rs +++ b/agb/src/agbabi/mod.rs @@ -43,7 +43,7 @@ mod test { for size in 0..68 { for (i, value) in input.iter_mut().enumerate() { - *value = i as u8 * 6; + *value = i as u8 * 3; } output.fill(0); @@ -61,5 +61,93 @@ mod test { } } } + + #[test_case] + fn test_memcpy_bytes_output_offsetted_with_different_sizes(_gba: &mut Gba) { + let mut input = vec![0u8; 70]; + let mut output = vec![0u8; 70]; + + for size in 0..60 { + for (i, value) in input.iter_mut().enumerate() { + *value = i as u8 * 3; + } + + output.fill(0); + + unsafe { + __agbabi_memcpy(output.as_mut_ptr().add(1), input.as_ptr(), size); + } + + for i in 0..size { + assert_eq!( + input[i], + output[i + 1], + "Failed with size = {size} at i = {i}" + ); + } + + for (i, value) in output.iter().enumerate().skip(size + 1) { + assert_eq!(*value, 0, "overrun with size = {size} at i = {i}"); + } + } + } + + #[test_case] + fn test_memcpy_bytes_input_offsetted_with_different_sizes(_gba: &mut Gba) { + let mut input = vec![0u8; 70]; + let mut output = vec![0u8; 70]; + + for size in 0..60 { + for (i, value) in input.iter_mut().enumerate() { + *value = i as u8 * 3; + } + + output.fill(0); + + unsafe { + __agbabi_memcpy(output.as_mut_ptr(), input.as_ptr().add(1), size); + } + + for i in 0..size { + assert_eq!( + input[i + 1], + output[i], + "Failed with size = {size} at i = {i}" + ); + } + + for (i, value) in output.iter().enumerate().skip(size) { + assert_eq!(*value, 0, "overrun with size = {size} at i = {i}"); + } + } + } + + #[test_case] + fn test_memcpy_bytes_input_output_offsetted_with_different_sizes(_gba: &mut Gba) { + let mut input = vec![0u8; 70]; + let mut output = vec![0u8; 70]; + + for size in 0..60 { + for (i, value) in input.iter_mut().enumerate() { + *value = i as u8 * 3; + } + + output.fill(0); + + unsafe { + __agbabi_memcpy(output.as_mut_ptr().add(1), input.as_ptr().add(1), size); + } + + assert_eq!(output[0], 0); + + for i in 1..size + 1 { + assert_eq!(input[i], output[i], "Failed with size = {size} at i = {i}"); + } + + for (i, value) in output.iter().enumerate().skip(size + 1) { + assert_eq!(*value, 0, "overrun with size = {size} at i = {i}"); + } + } + } } } From c9f1401ef3ab5e5c78b27016a8332691d05ca2af Mon Sep 17 00:00:00 2001 From: Gwilym Kuiper Date: Sun, 19 Jun 2022 13:03:44 +0100 Subject: [PATCH 3/3] Fix issue with small, misaligned copies --- agb/src/agbabi/memcpy.s | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/agb/src/agbabi/memcpy.s b/agb/src/agbabi/memcpy.s index 0c7412b5..8f6b6018 100644 --- a/agb/src/agbabi/memcpy.s +++ b/agb/src/agbabi/memcpy.s @@ -29,6 +29,10 @@ __aeabi_memcpy: bmi .Lcopy1 bcs .Lcopy2 + // If the number of bytes to copy is less than 4, we should just copy one byte at a time + cmp r2, #4 + bmi .Lcopy1 + .Lcopy4: // Copy half and byte head rsb r3, r0, #4