binary pim code for reduced memory usage
Validate Operations / validate-operations (push) Has been cancelled

fast pim code emission
This commit is contained in:
NiccoloN
2026-05-13 11:15:54 +02:00
parent 41de3cb150
commit 0c7db55a24
18 changed files with 1289 additions and 261 deletions
@@ -1,6 +1,7 @@
use anyhow::{Context, Result, bail};
use clap::Parser;
use glob::glob;
use pimcore::binary_to_instruction::binary_to_executor;
use pimcore::cpu::crossbar::Crossbar;
use pimcore::json_to_instruction::json_to_executor;
use pimcore::memory_manager::CoreMemory;
@@ -44,12 +45,14 @@ fn main() -> Result<()> {
let args = Args::parse();
let config_json = retrive_config(&args)?;
let core_jsons = retrive_cores(&args)?;
let core_inputs = retrive_cores(&args)?;
let memory = retrive_memory(&args)?;
let global_crossbars = get_crossbars(&config_json, &args).unwrap();
let crossbars = map_crossbars_to_cores(&config_json, &args, &global_crossbars);
let mut executor =
json_to_executor::json_to_executor(config_json, core_jsons.iter(), crossbars);
let mut executor = match &core_inputs {
CoreInputs::Json(core_jsons) => json_to_executor::json_to_executor(config_json, core_jsons.iter(), crossbars),
CoreInputs::Binary(core_bins) => binary_to_executor(config_json, core_bins.iter(), crossbars)?,
};
set_memory(&mut executor, memory);
TRACER
.lock()
@@ -214,9 +217,29 @@ fn retrive_memory(args: &Args) -> Result<Vec<u8>> {
Ok(memory_vector)
}
fn retrive_cores(args: &Args) -> Result<Vec<Value>, anyhow::Error> {
let mut core_jsons: Vec<Value> = Vec::new();
enum CoreInputs {
Json(Vec<Value>),
Binary(Vec<Vec<u8>>),
}
fn retrive_cores(args: &Args) -> Result<CoreInputs, anyhow::Error> {
if let Some(cores_override) = &args.cores {
let first_extension = cores_override
.first()
.and_then(|path| path.extension())
.and_then(|ext| ext.to_str())
.unwrap_or_default();
if first_extension == "pim" {
let mut core_bins = Vec::with_capacity(cores_override.len());
for core in cores_override {
core_bins.push(
fs::read(core)
.with_context(|| format!("Failed to read binary core file: {:?}", core))?,
);
}
return Ok(CoreInputs::Binary(core_bins));
}
let mut core_jsons: Vec<Value> = Vec::with_capacity(cores_override.len());
for core in cores_override {
let content = fs::read_to_string(core)
.with_context(|| format!("Failed to read core file: {:?}", cores_override))?;
@@ -224,35 +247,56 @@ fn retrive_cores(args: &Args) -> Result<Vec<Value>, anyhow::Error> {
serde_json::from_str(&content).context("Failed to parse core json override")?;
core_jsons.push(json);
}
} else if let Some(folder) = args.folder.as_ref() {
let pattern = folder.join("core*.json");
let pattern_str = pattern.to_str().context("Invalid path encoding")?;
let mut paths: Vec<_> = glob(pattern_str)?.map(|x| x.unwrap()).collect();
paths.sort_by_cached_key(|x| {
let mut x = x
.file_stem()
.expect("Extracting the stem")
.to_str()
.expect("File not utf-8");
x = &x[5..];
x.parse::<i32>().unwrap()
});
return Ok(CoreInputs::Json(core_jsons));
}
if paths.is_empty() {
bail!("No core*.json files found in {:?}", folder);
if let Some(folder) = args.folder.as_ref() {
let binary_pattern = folder.join("core*.pim");
let binary_pattern_str = binary_pattern.to_str().context("Invalid path encoding")?;
let mut binary_paths: Vec<_> = glob(binary_pattern_str)?.map(|x| x.unwrap()).collect();
binary_paths.sort_by_cached_key(core_sort_key);
if !binary_paths.is_empty() {
let mut core_bins = Vec::with_capacity(binary_paths.len());
for path in binary_paths {
core_bins.push(
fs::read(&path)
.with_context(|| format!("Failed to read core file: {:?}", path))?,
);
}
return Ok(CoreInputs::Binary(core_bins));
}
for entry in paths {
let path = entry;
let json_pattern = folder.join("core*.json");
let json_pattern_str = json_pattern.to_str().context("Invalid path encoding")?;
let mut json_paths: Vec<_> = glob(json_pattern_str)?.map(|x| x.unwrap()).collect();
json_paths.sort_by_cached_key(core_sort_key);
if json_paths.is_empty() {
bail!("No core*.pim or core*.json files found in {:?}", folder);
}
let mut core_jsons: Vec<Value> = Vec::with_capacity(json_paths.len());
for path in json_paths {
let content = fs::read_to_string(&path)
.with_context(|| format!("Failed to read core file: {:?}", path))?;
let json: Value = serde_json::from_str(&content)
.with_context(|| format!("Failed to parse JSON in {:?}", path))?;
core_jsons.push(json);
}
} else {
bail!("Either --core or --folder must be provided to find core definitions.");
return Ok(CoreInputs::Json(core_jsons));
}
Ok(core_jsons)
bail!("Either --core or --folder must be provided to find core definitions.");
}
fn core_sort_key(path: &PathBuf) -> i32 {
let mut stem = path
.file_stem()
.expect("Extracting the stem")
.to_str()
.expect("File not utf-8");
stem = &stem[5..];
stem.parse::<i32>().unwrap()
}
fn retrive_config(args: &Args) -> Result<Value, anyhow::Error> {
@@ -0,0 +1,497 @@
use crate::{
CoreInstructionsBuilder, Executable,
cpu::{CPU, crossbar::Crossbar},
instruction_set::{InstructionsBuilder, instruction_data::InstructionDataBuilder, isa::*},
};
use anyhow::{Context, Result, bail, ensure};
use serde_json::Value;
use std::collections::HashMap;
use std::convert::TryFrom;
use std::sync::LazyLock;
const MAGIC: &[u8; 4] = b"PIMB";
const VERSION: u32 = 1;
const HEADER_SIZE: usize = 12;
const RECORD_SIZE: usize = 20;
macro_rules! add_name {
($storage:ident, $opcode:literal, $name:literal) => {
$storage.insert($opcode, $name);
};
}
static INSTRUCTIONS: LazyLock<HashMap<usize, &'static str>> = LazyLock::new(|| {
let mut hash = HashMap::new();
add_name!(hash, 0, "nop");
add_name!(hash, 1, "sldi");
add_name!(hash, 2, "sld");
add_name!(hash, 3, "sadd");
add_name!(hash, 4, "ssub");
add_name!(hash, 5, "smul");
add_name!(hash, 6, "saddi");
add_name!(hash, 7, "smuli");
add_name!(hash, 8, "setbw");
add_name!(hash, 9, "mvmul");
add_name!(hash, 10, "vvadd");
add_name!(hash, 11, "vvsub");
add_name!(hash, 12, "vvmul");
add_name!(hash, 13, "vvdmul");
add_name!(hash, 14, "vvmax");
add_name!(hash, 15, "vvsll");
add_name!(hash, 16, "vvsra");
add_name!(hash, 17, "vavg");
add_name!(hash, 18, "vrelu");
add_name!(hash, 19, "vtanh");
add_name!(hash, 20, "vsigm");
add_name!(hash, 21, "vsoftmax");
add_name!(hash, 22, "vmv");
add_name!(hash, 23, "vrsu");
add_name!(hash, 24, "vrsl");
add_name!(hash, 25, "ld");
add_name!(hash, 26, "st");
add_name!(hash, 27, "lldi");
add_name!(hash, 28, "lmv");
add_name!(hash, 29, "send");
add_name!(hash, 30, "recv");
add_name!(hash, 31, "wait");
add_name!(hash, 32, "sync");
hash
});
#[derive(Clone, Copy, Debug, Default)]
struct InstructionRecord {
opcode: u8,
rd: u8,
r1: u8,
r2_or_imm: i32,
generic1: i32,
generic2: i32,
generic3: i32,
flags: u8,
}
fn read_u32_le(bytes: &[u8], offset: usize) -> u32 {
u32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())
}
fn read_i32_le(bytes: &[u8], offset: usize) -> i32 {
i32::from_le_bytes(bytes[offset..offset + 4].try_into().unwrap())
}
fn parse_binary_records(bytes: &[u8]) -> Result<Vec<InstructionRecord>> {
ensure!(bytes.len() >= HEADER_SIZE, "binary core file too small");
ensure!(&bytes[0..4] == MAGIC, "invalid PIM binary magic");
let version = read_u32_le(bytes, 4);
ensure!(
version == VERSION,
"unsupported PIM binary version {version}"
);
let instruction_count = read_u32_le(bytes, 8) as usize;
let expected_len = HEADER_SIZE + instruction_count * RECORD_SIZE;
ensure!(
bytes.len() == expected_len,
"PIM binary size mismatch: expected {expected_len} bytes, got {}",
bytes.len()
);
let mut records = Vec::with_capacity(instruction_count);
for index in 0..instruction_count {
let base = HEADER_SIZE + index * RECORD_SIZE;
records.push(InstructionRecord {
opcode: bytes[base],
rd: bytes[base + 1],
r1: bytes[base + 2],
flags: bytes[base + 3],
r2_or_imm: read_i32_le(bytes, base + 4),
generic1: read_i32_le(bytes, base + 8),
generic2: read_i32_le(bytes, base + 12),
generic3: read_i32_le(bytes, base + 16),
});
}
Ok(records)
}
fn append_record(
inst_builder: &mut InstructionsBuilder,
inst_data_builder: &mut InstructionDataBuilder,
record: InstructionRecord,
) -> Result<()> {
let InstructionRecord {
opcode,
rd,
r1,
r2_or_imm,
generic1,
generic2,
generic3,
flags: _,
} = record;
match opcode {
0 => {}
1 => {
inst_data_builder.set_rd_u8(rd).set_imm(r2_or_imm);
inst_builder.make_inst(sldi, inst_data_builder.build());
}
2 => {
inst_data_builder
.set_rd_u8(rd)
.set_r1_u8(r1)
.set_offset_select(generic1)
.set_offset_value(generic2);
inst_builder.make_inst(sld, inst_data_builder.build());
}
3 => {
inst_data_builder.set_rdr1r2_u8(rd, r1, r2_or_imm);
inst_builder.make_inst(sadd, inst_data_builder.build());
}
4 => {
inst_data_builder.set_rdr1r2_u8(rd, r1, r2_or_imm);
inst_builder.make_inst(ssub, inst_data_builder.build());
}
5 => {
inst_data_builder.set_rdr1r2_u8(rd, r1, r2_or_imm);
inst_builder.make_inst(smul, inst_data_builder.build());
}
6 => {
inst_data_builder.set_rdr1imm_u8(rd, r1, r2_or_imm);
inst_builder.make_inst(saddi, inst_data_builder.build());
}
7 => {
inst_data_builder.set_rdr1imm_u8(rd, r1, r2_or_imm);
inst_builder.make_inst(smuli, inst_data_builder.build());
}
8 => {
inst_data_builder.set_ibiw_obiw(generic1, generic2);
inst_builder.make_inst(setbw, inst_data_builder.build());
}
9 => {
inst_data_builder
.set_rd_u8(rd)
.set_r1_u8(r1)
.set_mbiw_immrelu_immgroup(r2_or_imm, generic1, generic2);
inst_builder.make_inst(mvmul, inst_data_builder.build());
}
10 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvadd, inst_data_builder.build());
}
11 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvsub, inst_data_builder.build());
}
12 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvmul, inst_data_builder.build());
}
13 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvdmul, inst_data_builder.build());
}
14 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvmax, inst_data_builder.build());
}
15 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvsll, inst_data_builder.build());
}
16 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vvsra, inst_data_builder.build());
}
17 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vavg, inst_data_builder.build());
}
18 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vrelu, inst_data_builder.build());
}
19 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vtanh, inst_data_builder.build());
}
20 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vsigm, inst_data_builder.build());
}
21 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vsoftmax, inst_data_builder.build());
}
22 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vmv, inst_data_builder.build());
}
23 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vrsu, inst_data_builder.build());
}
24 => {
inst_data_builder
.set_rdr1r2_u8(rd, r1, r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(vrsl, inst_data_builder.build());
}
25 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(ld, inst_data_builder.build());
}
26 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(st, inst_data_builder.build());
}
27 => {
inst_data_builder
.set_rd_u8(rd)
.set_imm(r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(lldi, inst_data_builder.build());
}
28 => {
inst_data_builder
.set_rdr1_u8(rd, r1)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(lmv, inst_data_builder.build());
}
29 => {
inst_data_builder
.set_rd_u8(rd)
.set_imm_core(r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(send, inst_data_builder.build());
}
30 => {
inst_data_builder
.set_rd_u8(rd)
.set_imm_core(r2_or_imm)
.set_imm_len(generic3)
.set_offset_select_value(generic1, generic2);
inst_builder.make_inst(recv, inst_data_builder.build());
}
31 => {
inst_builder.make_inst(wait, inst_data_builder.build());
}
32 => {
inst_builder.make_inst(sync, inst_data_builder.build());
}
_ => bail!("unsupported PIM binary opcode {opcode}"),
}
Ok(())
}
fn binary_to_instructions(
core_bytes: &[u8],
core_index: i32,
) -> Result<Vec<crate::instruction_set::Instruction>> {
let records = parse_binary_records(core_bytes)?;
let mut insts_builder = InstructionsBuilder::new();
let mut inst_data_builder = InstructionDataBuilder::new();
inst_data_builder
.set_core_indx_u16(u16::try_from(core_index).expect("core index does not fit in u16"))
.fix_core_indx();
for record in records {
let opcode = record.opcode;
let name = INSTRUCTIONS
.get(&(opcode as usize))
.copied()
.unwrap_or("<unknown>");
append_record(&mut insts_builder, &mut inst_data_builder, record).with_context(|| {
format!(
"while decoding binary instruction for core {core_index}: opcode {opcode} ({name})"
)
})?;
}
Ok(insts_builder.build())
}
pub fn binary_to_executor<'a, 'b>(
config: Value,
mut cores: impl Iterator<Item = &'b Vec<u8>>,
crossbars: Vec<Vec<&'a Crossbar>>,
) -> Result<Executable<'a>> {
let core_cnt = config
.get("core_cnt")
.context("missing core_cnt in config")?
.as_i64()
.context("core_cnt is not an integer")? as i32
- 1;
let cpu = CPU::new(core_cnt, crossbars);
let mut core_insts_builder = CoreInstructionsBuilder::new(core_cnt as usize);
cores.next();
for core_indx in 1..=core_cnt {
let core_bytes = cores
.next()
.unwrap_or_else(|| panic!("cores files less than {}", core_indx));
let instructions = binary_to_instructions(core_bytes, core_indx)?;
core_insts_builder.set_core(core_indx, instructions);
}
Ok(Executable::new(cpu, core_insts_builder.build()))
}
#[cfg(test)]
mod tests {
use super::{
HEADER_SIZE, InstructionRecord, MAGIC, RECORD_SIZE, VERSION, binary_to_instructions,
};
use crate::{
instruction_set::{InstructionsBuilder, instruction_data::InstructionDataBuilder},
json_to_instruction::json_isa::json_to_instruction,
};
fn encode_record(record: InstructionRecord, dst: &mut Vec<u8>) {
dst.push(record.opcode);
dst.push(record.rd);
dst.push(record.r1);
dst.push(record.flags);
dst.extend_from_slice(&record.r2_or_imm.to_le_bytes());
dst.extend_from_slice(&record.generic1.to_le_bytes());
dst.extend_from_slice(&record.generic2.to_le_bytes());
dst.extend_from_slice(&record.generic3.to_le_bytes());
}
fn binary_blob(records: &[InstructionRecord]) -> Vec<u8> {
let mut blob = Vec::with_capacity(HEADER_SIZE + records.len() * RECORD_SIZE);
blob.extend_from_slice(MAGIC);
blob.extend_from_slice(&VERSION.to_le_bytes());
blob.extend_from_slice(&(records.len() as u32).to_le_bytes());
for &record in records {
encode_record(record, &mut blob);
}
blob
}
#[test]
fn json_and_binary_decoders_match_for_representative_ops() {
let json_program = [
r#"{"imm":64,"op":"sldi","rd":0}"#,
r#"{"imm":128,"op":"sldi","rd":1}"#,
r#"{"len":16,"offset":{"offset_select":0,"offset_value":0},"op":"lmv","rd":0,"rs1":1}"#,
r#"{"group":3,"mbiw":8,"op":"mvmul","rd":0,"relu":0,"rs1":1}"#,
r#"{"len":16,"offset":{"offset_select":0,"offset_value":0},"op":"vvadd","rd":0,"rs1":1,"rs2":2}"#,
r#"{"core":2,"offset":{"offset_select":0,"offset_value":0},"op":"send","rd":0,"size":16}"#,
];
let binary_program = binary_blob(&[
InstructionRecord {
opcode: 1,
rd: 0,
r2_or_imm: 64,
..Default::default()
},
InstructionRecord {
opcode: 1,
rd: 1,
r2_or_imm: 128,
..Default::default()
},
InstructionRecord {
opcode: 28,
rd: 0,
r1: 1,
generic3: 16,
..Default::default()
},
InstructionRecord {
opcode: 9,
rd: 0,
r1: 1,
r2_or_imm: 8,
generic2: 3,
..Default::default()
},
InstructionRecord {
opcode: 10,
rd: 0,
r1: 1,
r2_or_imm: 2,
generic3: 16,
..Default::default()
},
InstructionRecord {
opcode: 29,
rd: 0,
r2_or_imm: 2,
generic3: 16,
..Default::default()
},
]);
let mut json_builder = InstructionsBuilder::new();
let mut json_data_builder = InstructionDataBuilder::new();
json_data_builder.set_core_indx(1).fix_core_indx();
for inst in json_program {
let value = serde_json::from_str(inst).unwrap();
json_to_instruction(&mut json_builder, &mut json_data_builder, &value);
}
let json_instructions = json_builder.build();
let binary_instructions = binary_to_instructions(&binary_program, 1).unwrap();
assert_eq!(json_instructions.len(), binary_instructions.len());
for (json_inst, binary_inst) in json_instructions.iter().zip(binary_instructions.iter()) {
assert_eq!(json_inst.functor_name(), binary_inst.functor_name());
assert_eq!(json_inst.data, binary_inst.data);
}
}
}
@@ -1,10 +1,11 @@
use paste::paste;
use std::convert::TryFrom;
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct InstructionData {
core_indx: i32,
rd: i32,
r1: i32,
core_indx: u16,
rd: u8,
r1: u8,
//r2 imm mbiw imm_core
r2_or_imm: i32,
//offset_select imm_relu ibiw
@@ -16,18 +17,30 @@ pub struct InstructionData {
}
impl InstructionData {
pub fn core_indx(&self) -> i32 {
pub fn core_indx_u16(&self) -> u16 {
self.core_indx
}
pub fn rd(&self) -> i32 {
pub fn core_indx(&self) -> i32 {
i32::from(self.core_indx)
}
pub fn rd_u8(&self) -> u8 {
self.rd
}
pub fn r1(&self) -> i32 {
pub fn rd(&self) -> i32 {
i32::from(self.rd)
}
pub fn r1_u8(&self) -> u8 {
self.r1
}
pub fn r1(&self) -> i32 {
i32::from(self.r1)
}
pub fn r2(&self) -> i32 {
self.r2_or_imm
}
@@ -49,26 +62,26 @@ impl InstructionData {
}
pub fn get_core_rd_r1(&self) -> (i32, i32, i32) {
(self.core_indx, self.rd, self.r1)
(self.core_indx(), self.rd(), self.r1())
}
pub fn get_core_rd_r1_r2(&self) -> (i32, i32, i32, i32) {
(self.core_indx, self.rd, self.r1, self.r2_or_imm)
(self.core_indx(), self.rd(), self.r1(), self.r2_or_imm)
}
pub fn get_core_rd_imm(&self) -> (i32, i32, i32) {
(self.core_indx, self.rd, self.r2_or_imm)
(self.core_indx(), self.rd(), self.r2_or_imm)
}
pub fn get_core_rd_r1_imm(&self) -> (i32, i32, i32, i32) {
(self.core_indx, self.rd, self.r1, self.r2_or_imm)
(self.core_indx(), self.rd(), self.r1(), self.r2_or_imm)
}
pub fn get_core_rd_r1_r2_immlen_offset(&self) -> (i32, i32, i32, i32, i32, i32, i32) {
(
self.core_indx,
self.rd,
self.r1,
self.core_indx(),
self.rd(),
self.r1(),
self.r2_or_imm,
self.generic3,
self.generic1,
@@ -78,9 +91,9 @@ impl InstructionData {
pub fn get_core_rd_r1_mbiw_immrelu_immgroup(&self) -> (i32, i32, i32, i32, i32, i32) {
(
self.core_indx,
self.rd,
self.r1,
self.core_indx(),
self.rd(),
self.r1(),
self.r2_or_imm,
self.generic1,
self.generic2,
@@ -100,7 +113,7 @@ impl InstructionData {
}
pub(crate) fn get_core_immcore(&self) -> (i32, i32) {
(self.core_indx, self.r2_or_imm)
(self.core_indx(), self.r2_or_imm)
}
}
@@ -216,6 +229,18 @@ impl InstructionDataBuilder {
common_getter_setter![imm_group];
common_getter_setter![imm_core];
pub fn set_core_indx_u16(&mut self, val: u16) -> &mut Self {
self.set_core_indx(i32::from(val))
}
pub fn set_rd_u8(&mut self, val: u8) -> &mut Self {
self.set_rd(i32::from(val))
}
pub fn set_r1_u8(&mut self, val: u8) -> &mut Self {
self.set_r1(i32::from(val))
}
pub fn new() -> Self {
Self {
core_indx: Fixer::Edit(0),
@@ -254,20 +279,16 @@ impl InstructionDataBuilder {
fn check_sanity(&self) {
assert!(!(self.get_r2() != 0 && self.get_imm() != 0 && self.get_mbiw() != 0 && self.get_imm_core() != 0));
assert!(
!(self.get_ibiw() != 0 && self.get_offset_select() != 0 && self.get_imm_relu() != 0)
);
assert!(
!(self.get_obiw() != 0 && self.get_offset_value() != 0 && self.get_imm_group() != 0)
);
assert!(!(self.get_ibiw() != 0 && self.get_offset_select() != 0 && self.get_imm_relu() != 0));
assert!(!(self.get_obiw() != 0 && self.get_offset_value() != 0 && self.get_imm_group() != 0));
}
pub fn build(&mut self) -> InstructionData {
self.check_sanity();
let inst_data = InstructionData {
core_indx: self.get_core_indx(),
rd: self.get_rd(),
r1: self.get_r1(),
core_indx: u16::try_from(self.get_core_indx()).expect("core index does not fit in u16"),
rd: u8::try_from(self.get_rd()).expect("rd does not fit in u8"),
r1: u8::try_from(self.get_r1()).expect("r1 does not fit in u8"),
r2_or_imm: self.get_r2() + self.get_imm() + self.get_mbiw() + self.get_imm_core(),
generic1: self.get_offset_select() + self.get_ibiw() + self.get_imm_relu(),
generic2: self.get_offset_value() + self.get_obiw() + self.get_imm_group(),
@@ -281,6 +302,10 @@ impl InstructionDataBuilder {
self.set_rd(rd).set_r1(r1).set_r2(r2)
}
pub fn set_rdr1r2_u8(&mut self, rd: u8, r1: u8, r2: i32) -> &mut Self {
self.set_rd_u8(rd).set_r1_u8(r1).set_r2(r2)
}
pub fn set_offset_select_value(&mut self, offset_select: i32, offset_value: i32) -> &mut Self {
self.set_offset_select(offset_select)
.set_offset_value(offset_value)
@@ -290,14 +315,26 @@ impl InstructionDataBuilder {
self.set_rd(rd).set_r1(r1).set_imm(imm)
}
pub fn set_rdr1imm_u8(&mut self, rd: u8, r1: u8, imm: i32) -> &mut Self {
self.set_rd_u8(rd).set_r1_u8(r1).set_imm(imm)
}
pub fn set_rdr1(&mut self, rd: i32, r1: i32) -> &mut Self {
self.set_rd(rd).set_r1(r1)
}
pub fn set_rdr1_u8(&mut self, rd: u8, r1: u8) -> &mut Self {
self.set_rd_u8(rd).set_r1_u8(r1)
}
pub fn set_rdimm(&mut self, rd: i32, imm: i32) -> &mut Self {
self.set_rd(rd).set_imm(imm)
}
pub fn set_rdimm_u8(&mut self, rd: u8, imm: i32) -> &mut Self {
self.set_rd_u8(rd).set_imm(imm)
}
pub fn set_ibiw_obiw(&mut self, ibiw: i32, obiw: i32) -> &mut Self {
self.set_ibiw(ibiw).set_obiw(obiw)
}
@@ -10,6 +10,7 @@ use crate::{
tracing::TRACER,
};
pub mod cpu;
pub mod binary_to_instruction;
pub mod instruction_set;
pub mod json_to_instruction;
pub mod memory_manager;