use super::functions::*;
use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
#[allow(dead_code)]
pub struct MemoryLayout {
pub type_name: String,
pub size: usize,
pub align: usize,
}
#[allow(dead_code)]
impl MemoryLayout {
pub fn new(type_name: impl Into<String>, size: usize, align: usize) -> Self {
Self {
type_name: type_name.into(),
size,
align,
}
}
pub fn stride(&self) -> usize {
(self.size + self.align - 1) & !(self.align - 1)
}
pub fn is_valid(&self) -> bool {
self.align > 0 && self.align.is_power_of_two() && self.size <= self.stride()
}
pub fn align_offset(&self, offset: usize) -> usize {
let mask = self.align - 1;
(offset + mask) & !mask
}
pub fn describe(&self) -> String {
format!(
"{}: size={}, align={}, stride={}",
self.type_name,
self.size,
self.align,
self.stride()
)
}
}
#[allow(dead_code)]
pub struct CStructLayout {
pub name: String,
pub fields: Vec<(String, usize, usize)>,
}
#[allow(dead_code)]
impl CStructLayout {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
fields: Vec::new(),
}
}
pub fn add_field(mut self, name: impl Into<String>, size: usize, align: usize) -> Self {
self.fields.push((name.into(), size, align));
self
}
pub fn field_offset(&self, idx: usize) -> usize {
let mut offset = 0usize;
for (i, (_, size, align)) in self.fields.iter().enumerate() {
let mask = align - 1;
offset = (offset + mask) & !mask;
if i == idx {
return offset;
}
offset += size;
}
offset
}
pub fn total_size(&self) -> usize {
if self.fields.is_empty() {
return 0;
}
let max_align = self.fields.iter().map(|(_, _, a)| *a).max().unwrap_or(1);
let mut offset = 0usize;
for (_, size, align) in &self.fields {
let mask = align - 1;
offset = (offset + mask) & !mask;
offset += size;
}
let mask = max_align - 1;
(offset + mask) & !mask
}
pub fn describe(&self) -> String {
let offsets: Vec<String> = (0..self.fields.len())
.map(|i| {
format!(
" [{}] {} @ offset {}",
i,
self.fields[i].0,
self.field_offset(i)
)
})
.collect();
format!(
"struct {} {{\n{}\n}} size={}",
self.name,
offsets.join("\n"),
self.total_size()
)
}
}
#[allow(dead_code)]
pub enum PointerKind {
Raw,
Fat { metadata_size: usize },
Tagged { tag_bits: u32 },
VTable { num_methods: usize },
}
#[allow(dead_code)]
pub struct PointerRepr {
pub kind: PointerKind,
pub addr_bytes: usize,
}
#[allow(dead_code)]
impl PointerRepr {
pub fn raw64() -> Self {
Self {
kind: PointerKind::Raw,
addr_bytes: 8,
}
}
pub fn fat64(metadata_size: usize) -> Self {
Self {
kind: PointerKind::Fat { metadata_size },
addr_bytes: 8,
}
}
pub fn tagged(tag_bits: u32) -> Self {
Self {
kind: PointerKind::Tagged { tag_bits },
addr_bytes: 8,
}
}
pub fn total_size(&self) -> usize {
match &self.kind {
PointerKind::Raw => self.addr_bytes,
PointerKind::Fat { metadata_size } => self.addr_bytes + metadata_size,
PointerKind::Tagged { .. } => self.addr_bytes,
PointerKind::VTable { .. } => self.addr_bytes * 2,
}
}
pub fn describe(&self) -> String {
match &self.kind {
PointerKind::Raw => format!("*raw ({} bytes)", self.addr_bytes),
PointerKind::Fat { metadata_size } => {
format!(
"*fat (addr={} meta={} total={})",
self.addr_bytes,
metadata_size,
self.total_size()
)
}
PointerKind::Tagged { tag_bits } => {
format!("*tagged ({} tag bits, {} bytes)", tag_bits, self.addr_bytes)
}
PointerKind::VTable { num_methods } => {
format!(
"*dyn ({} methods, {} bytes)",
num_methods,
self.total_size()
)
}
}
}
}
#[allow(dead_code)]
pub struct Ieee754Descriptor {
pub name: String,
pub total_bits: u32,
pub exponent_bits: u32,
pub mantissa_bits: u32,
}
#[allow(dead_code)]
impl Ieee754Descriptor {
pub fn new(name: impl Into<String>, total: u32, exp: u32, mant: u32) -> Self {
Self {
name: name.into(),
total_bits: total,
exponent_bits: exp,
mantissa_bits: mant,
}
}
pub fn binary32() -> Self {
Self::new("binary32", 32, 8, 23)
}
pub fn binary64() -> Self {
Self::new("binary64", 64, 11, 52)
}
pub fn exponent_bias(&self) -> u32 {
(1u32 << (self.exponent_bits - 1)) - 1
}
pub fn max_exponent(&self) -> i32 {
self.exponent_bias() as i32
}
pub fn is_valid(&self) -> bool {
self.total_bits == 1 + self.exponent_bits + self.mantissa_bits
}
pub fn describe(&self) -> String {
format!(
"{}: total={} sign=1 exp={} mant={} bias={}",
self.name,
self.total_bits,
self.exponent_bits,
self.mantissa_bits,
self.exponent_bias()
)
}
}
#[allow(dead_code)]
pub struct BitfieldDescriptor {
pub name: String,
pub offset: u32,
pub width: u32,
}
#[allow(dead_code)]
impl BitfieldDescriptor {
pub fn new(name: impl Into<String>, offset: u32, width: u32) -> Self {
Self {
name: name.into(),
offset,
width,
}
}
pub fn mask(&self) -> u64 {
let raw = if self.width >= 64 {
!0u64
} else {
(1u64 << self.width) - 1
};
raw << self.offset
}
pub fn extract(&self, word: u64) -> u64 {
(word & self.mask()) >> self.offset
}
pub fn insert(&self, word: u64, value: u64) -> u64 {
let m = self.mask();
(word & !m) | ((value << self.offset) & m)
}
pub fn fits_in(&self, word_bits: u32) -> bool {
self.offset + self.width <= word_bits
}
}
#[allow(dead_code)]
pub struct RegisterFileState {
pub regs: Vec<u64>,
}
#[allow(dead_code)]
impl RegisterFileState {
pub fn new(count: usize) -> Self {
Self {
regs: vec![0u64; count],
}
}
pub fn read(&self, r: usize) -> Option<u64> {
self.regs.get(r).copied()
}
pub fn write(&mut self, r: usize, value: u64) {
if r < self.regs.len() {
self.regs[r] = value;
}
}
pub fn verify_raw(&mut self, r: usize, v: u64) -> bool {
self.write(r, v);
self.read(r) == Some(v)
}
pub fn count(&self) -> usize {
self.regs.len()
}
pub fn describe(&self) -> String {
let parts: Vec<String> = self
.regs
.iter()
.enumerate()
.map(|(i, v)| format!("r{}=0x{:x}", i, v))
.collect();
format!("[{}]", parts.join(", "))
}
}