Skip to content

Commit

Permalink
Wire up function bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
AngheloAlf committed Dec 15, 2023
1 parent 9b26d15 commit 39aa352
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 37 deletions.
78 changes: 54 additions & 24 deletions src/rs/checksum.rs
Original file line number Diff line number Diff line change
@@ -1,52 +1,46 @@
/* SPDX-FileCopyrightText: © 2023 Decompollaborate */
/* SPDX-License-Identifier: MIT */

#[cfg(feature = "python_bindings")]
use pyo3::prelude::*;

use crate::cickinds::CICKind;
use crate::utils;

use crate::{utils, detect};

fn readWordFromRam(romWords: &[u32], entrypointRam: u32, ramAddr: u32) -> u32 {
//return romWords[utils.u32(ramAddr - entrypointRam + 0x1000) / 4]
romWords[((ramAddr - entrypointRam + 0x1000) / 4) as usize]
fn read_word_from_ram(rom_words: &[u32], entrypoint_ram: u32, ram_addr: u32) -> u32 {
rom_words[((ram_addr - entrypoint_ram + 0x1000) / 4) as usize]
}


pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)> {
pub fn calculate_checksum(rom_bytes: &[u8], kind: &CICKind) -> Option<(u32, u32)> {
/*
Calculates the checksum required by an official CIC of a N64 ROM.
Args:
romBytes (bytes): The bytes of the N64 ROM in big endian format. It must have a minimum size of 0x101000 bytes.
rom_bytes (bytes): The bytes of the N64 ROM in big endian format. It must have a minimum size of 0x101000 bytes.
kind (CICKind): The CIC kind variation used to calculate the checksum.
Returns:
tuple[int, int]|None: If no error happens then the calculated checksum is returned, stored as a tuple
containing two 32-bits words. Otherwise, `None` is returned. Possible errors:
- `romBytes` not being big enough
- `rom_bytes` not being big enough
*/

if romBytes.len() < 0x101000 {
if rom_bytes.len() < 0x101000 {
return None;
}

let romWords = utils::read_u32_vec(romBytes, 0, 0x101000/4);
let rom_words = utils::read_u32_vec(rom_bytes, 0, 0x101000/4);

let seed = kind.get_seed();
let magic = kind.get_magic();

let mut s6 = seed;

let mut a0 = romWords[8/4];
let mut a0 = rom_words[8/4];
if *kind == CICKind::CIC_X103 {
a0 = a0.wrapping_sub(0x100000);
}
if *kind == CICKind::CIC_X106 {
a0 = a0.wrapping_sub(0x200000);
}
let entrypointRam = a0;
let entrypoint_ram = a0;

let mut at = magic;
let lo = s6.wrapping_mul(at);
Expand All @@ -57,7 +51,6 @@ pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)>

let ra = 0x100000;

let mut v1: u32 = 0;
let mut t0: u32 = 0;

let mut t1: u32 = a0;
Expand All @@ -76,13 +69,14 @@ pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)>
let mut t4 = v0;

// poor man's do while
let mut LA40005F0_loop = true;
while LA40005F0_loop {
// LA40005F0_loop
let mut loop_variable = true;
while loop_variable {
// v0 = *t1
v0 = readWordFromRam(&romWords, entrypointRam, t1);
v0 = read_word_from_ram(&rom_words, entrypoint_ram, t1);

//v1 = utils.u32(a3 + v0);
v1 = a3.wrapping_add(v0);
let mut v1 = a3.wrapping_add(v0);

//at = utils.u32(v1) < utils.u32(a3);
at = if v1 < a3 { 1 } else { 0 };
Expand Down Expand Up @@ -131,7 +125,7 @@ pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)>
// LA4000640:
if *kind == CICKind::CIC_X105 {
// ipl3 6105 copies 0x330 bytes from the ROM's offset 0x000554 (or offset 0x000514 into IPL3) to vram 0xA0000004
let mut t7 = romWords[((s6 - 0xA0000004 + 0x000554) / 4) as usize];
let mut t7 = rom_words[((s6 - 0xA0000004 + 0x000554) / 4) as usize];

//t0 = utils.u32(t0 + 0x4);
//s6 = utils.u32(s6 + 0x4);
Expand Down Expand Up @@ -166,7 +160,7 @@ pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)>

// if (t0 != ra) goto LA40005F0;
if t0 == ra {
LA40005F0_loop = false;
loop_variable = false;
}
}

Expand Down Expand Up @@ -199,6 +193,26 @@ pub fn calculateChecksum(romBytes: &[u8], kind: &CICKind) -> Option<(u32, u32)>
return Some((a3, s0))
}

pub fn calculate_checksum_autodetect(rom_bytes: &[u8]) -> Option<(u32, u32)> {
/*Calculates the checksum required by an official CIC of a N64 ROM.
This function will try to autodetect the CIC kind automatically. If it fails to detect it then it will return `None`.
Args:
rom_bytes (bytes): The bytes of the N64 ROM in big endian format. It must have a minimum size of 0x101000 bytes.
Returns:
tuple[int, int]|None: If no error happens then the calculated checksum is returned, stored as a tuple
containing two 32-bits words. Otherwise, `None` is returned. Possible errors:
- `rom_bytes` not being big enough
- Not able to detect the CIC kind
*/

let kind = detect::detect_cic(rom_bytes)?;

calculate_checksum(rom_bytes, &kind)
}

#[cfg(test)]
mod tests {
//use rstest::rstest;
Expand Down Expand Up @@ -239,7 +253,7 @@ mod tests {
let bin_bytes = fs::read(&bin_path.path()).unwrap();

println!(" Calculating checksum...");
let checksum = super::calculateChecksum(&bin_bytes, &kind).unwrap();
let checksum = super::calculate_checksum(&bin_bytes, &kind).unwrap();

println!(" Calculated checksum is: 0x{:08X} 0x{:08X}", checksum.0, checksum.1);

Expand All @@ -261,3 +275,19 @@ mod tests {
Ok(())
}
}

#[cfg(feature = "python_bindings")]
#[allow(non_snake_case)]
pub(crate) mod python_bindings {
use pyo3::prelude::*;

#[pyfunction]
pub(crate) fn calculateChecksum(rom_bytes: &[u8], kind: &super::CICKind) -> Option<(u32, u32)> {
super::calculate_checksum(rom_bytes, kind)
}

#[pyfunction]
pub(crate) fn calculateChecksumAutodetect(rom_bytes: &[u8]) -> Option<(u32, u32)> {
super::calculate_checksum_autodetect(rom_bytes)
}
}
6 changes: 1 addition & 5 deletions src/rs/cickinds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,34 +77,30 @@ impl CICKind {
}

#[cfg(feature = "python_bindings")]
#[allow(non_snake_case)]
mod python_bindings {
use pyo3::prelude::*;

#[pymethods]
impl super::CICKind {
#[allow(non_snake_case)]
pub fn getSeed(&self) -> u32 {
self.get_seed()
}

#[allow(non_snake_case)]
pub fn getMagic(&self) -> u32 {
self.get_magic()
}

#[allow(non_snake_case)]
pub fn getHashMd5(&self) -> &str {
self.get_hash_md5()
}

#[staticmethod]
#[allow(non_snake_case)]
pub fn fromHashMd5(hash_str: &str) -> Option<super::CICKind> {
super::CICKind::from_hash_md5(hash_str)
}

#[staticmethod]
#[allow(non_snake_case)]
pub fn fromValue(value: usize) -> Option<super::CICKind> {
super::CICKind::from_value(value)
}
Expand Down
32 changes: 24 additions & 8 deletions src/rs/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,54 @@
use crate::cickinds::CICKind;
use crate::utils;

pub fn detectCICRaw(rawBytes: &[u8]) -> Option<CICKind> {
pub fn detect_cic_raw(raw_bytes: &[u8]) -> Option<CICKind> {
/*Tries to detect an IPL3 binary.
The argument to this function must be exactly the IPL3 binary, stripping the rest of the ROM.
Args:
rawBytes (bytes): IPL3 binary in big endian format.
raw_bytes (bytes): IPL3 binary in big endian format.
Returns:
CICKind|None: The detected CIC kind, or `None` if was not able to detect the CIC kind.
*/

if rawBytes.len() != 0xFC0 {
if raw_bytes.len() != 0xFC0 {
return None;
}

let bytesHash = utils::get_hash_md5(rawBytes);
let bytes_hash = utils::get_hash_md5(raw_bytes);

CICKind::from_hash_md5(&bytesHash)
CICKind::from_hash_md5(&bytes_hash)
}

pub fn detectCIC(romBytes: &[u8]) -> Option<CICKind> {
pub fn detect_cic(rom_bytes: &[u8]) -> Option<CICKind> {
/*Tries to detect an IPL3 in a ROM.
The argument to this function must be a ROM in big endian format.
Args:
romBytes (bytes): ROMbinary in big endian format.
rom_bytes (bytes): ROMbinary in big endian format.
Returns:
CICKind|None: The detected CIC kind, or `None` if was not able to detect the CIC kind.
*/

detectCICRaw(&romBytes[0x40..0x1000])
detect_cic_raw(&rom_bytes[0x40..0x1000])
}

#[cfg(feature = "python_bindings")]
#[allow(non_snake_case)]
pub(crate) mod python_bindings {
use pyo3::prelude::*;

#[pyfunction]
pub(crate) fn detectCICRaw(raw_bytes: &[u8]) -> Option<super::CICKind> {
super::detect_cic_raw(raw_bytes)
}

#[pyfunction]
pub(crate) fn detectCIC(rom_bytes: &[u8]) -> Option<super::CICKind> {
super::detect_cic(rom_bytes)
}
}
4 changes: 4 additions & 0 deletions src/rs/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use pyo3::prelude::*;
#[pymodule]
fn ipl3checksum(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
m.add_class::<cickinds::CICKind>()?;
m.add_function(wrap_pyfunction!(checksum::python_bindings::calculateChecksum, m)?)?;
m.add_function(wrap_pyfunction!(checksum::python_bindings::calculateChecksumAutodetect, m)?)?;
m.add_function(wrap_pyfunction!(detect::python_bindings::detectCICRaw, m)?)?;
m.add_function(wrap_pyfunction!(detect::python_bindings::detectCIC, m)?)?;
Ok(())
}

Expand Down

0 comments on commit 39aa352

Please sign in to comment.