use nom::{
multi::count,
number::complete::{be_i32, be_u8},
IResult,
};
use crate::{
base::{self, MIN_HALFWORD, SIZEOF_MEMORY_WORD},
engine::Engine,
parseutils,
};
pub type MemPointer = i32;
#[derive(Debug)]
pub struct Memory {
pub mem: Vec<u8>,
pub lo_mem_max: MemPointer,
}
const HI_MEM_STAT_USAGE: i32 = 15;
const N_SERIALIZED_SA_ROOTS: usize = 7;
impl Memory {
pub(crate) fn parse<'a>(input: &'a [u8], engine: &Engine) -> IResult<&'a [u8], Self> {
let mem_top = engine.symbols.lookup("MEM_TOP") as usize;
let (input, lo_mem_max) =
parseutils::ranged_be_i32(1019, mem_top as i32 - HI_MEM_STAT_USAGE)(input)?;
let (input, rover) = parseutils::ranged_be_i32(20, lo_mem_max)(input)?;
let (input, _sa_roots) = count(
parseutils::ranged_be_i32(MIN_HALFWORD, lo_mem_max),
N_SERIALIZED_SA_ROOTS,
)(input)?;
let mut mem = vec![0; (mem_top as usize + 1) * SIZEOF_MEMORY_WORD];
let mut input = input;
let mut p = 0;
let mut q = rover;
loop {
let nb = (q + 2 - p) as usize * SIZEOF_MEMORY_WORD;
let (new_input, block) = count(be_u8, nb)(input)?;
input = new_input;
let idx = p as usize * SIZEOF_MEMORY_WORD;
mem[idx..idx + nb].copy_from_slice(&block[..]);
let ofs = base::memword_read_b32_s0(&mem[..], q);
p = q + ofs;
assert!(p <= lo_mem_max);
q = base::memword_read_b32_s1(&mem[..], q + 1);
if q == rover {
break;
}
}
let nb = (lo_mem_max + 1 - p as i32) as usize * SIZEOF_MEMORY_WORD;
let (input, block) = count(be_u8, nb)(input)?;
let idx = p as usize * SIZEOF_MEMORY_WORD;
mem[idx..idx + nb].copy_from_slice(&block[..]);
let (input, hi_mem_min) =
parseutils::ranged_be_i32(lo_mem_max + 1, mem_top as i32 - HI_MEM_STAT_USAGE)(input)?;
let (input, _avail) = parseutils::ranged_be_i32(MIN_HALFWORD, mem_top as i32)(input)?;
let nb = (mem_top + 1 - hi_mem_min as usize) * SIZEOF_MEMORY_WORD;
let (input, block) = count(be_u8, nb)(input)?;
mem[hi_mem_min as usize * SIZEOF_MEMORY_WORD
..hi_mem_min as usize * SIZEOF_MEMORY_WORD + nb]
.copy_from_slice(&block[..]);
let (input, _var_used) = be_i32(input)?;
let (input, _dyn_used) = be_i32(input)?;
Ok((input, Memory { mem, lo_mem_max }))
}
pub fn decode_toklist(&self, index: MemPointer) -> (i32, MemPointer) {
let value = base::memword_read_b32_s0(&self.mem[..], index);
let next = base::memword_read_b32_s1(&self.mem[..], index);
(value, next)
}
}