use super::constant::*;
use super::module::*;
use super::signal::*;
use std::cell::RefCell;
use std::ptr;
#[must_use]
pub struct Register<'a> {
pub(crate) data: &'a RegisterData<'a>,
pub value: &'a Signal<'a>,
}
impl<'a> Register<'a> {
pub fn default_value<C: Into<Constant>>(&'a self, value: C) {
if self.data.initial_value.borrow().is_some() {
panic!("Attempted to specify a default value for register \"{}\" in module \"{}\", but this register already has a default value.", self.data.name, self.data.module.name);
}
let value = value.into();
let required_bits = value.required_bits();
if required_bits > self.data.bit_width {
let numeric_value = value.numeric_value();
panic!("Cannot fit the specified value '{}' into register \"{}\"'s bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, self.data.name, self.data.bit_width, numeric_value, required_bits);
}
*self.data.initial_value.borrow_mut() = Some(value);
}
pub fn drive_next(&'a self, n: &'a Signal<'a>) {
if !ptr::eq(self.data.module, n.module) {
panic!("Attempted to drive register \"{}\"'s next value with a signal from another module.", self.data.name);
}
if n.bit_width() != self.data.bit_width {
panic!("Attempted to drive register \"{}\"'s next value with a signal that has a different bit width than the register ({} and {}, respectively).", self.data.name, n.bit_width(), self.data.bit_width);
}
if self.data.next.borrow().is_some() {
panic!("Attempted to drive register \"{}\"'s next value in module \"{}\", but this register's next value is already driven.", self.data.name, self.data.module.name);
}
*self.data.next.borrow_mut() = Some(n);
}
}
pub(crate) struct RegisterData<'a> {
pub module: &'a Module<'a>,
pub name: String,
pub initial_value: RefCell<Option<Constant>>,
pub bit_width: u32,
pub next: RefCell<Option<&'a Signal<'a>>>,
}
#[cfg(test)]
mod tests {
use crate::*;
#[test]
#[should_panic(
expected = "Attempted to specify a default value for register \"r\" in module \"A\", but this register already has a default value."
)]
fn default_value_already_specified_error() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 32);
r.default_value(0xfadebabeu32);
r.default_value(0xdeadbeefu32);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
)]
fn default_value_cannot_bit_into_bit_width_error_1() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 7);
r.default_value(128u32);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '128' into register \"r\"'s bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
)]
fn default_value_cannot_bit_into_bit_width_error_2() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 2);
r.default_value(128u64);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '1023' into register \"r\"'s bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
)]
fn default_value_cannot_bit_into_bit_width_error_3() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 4);
r.default_value(1023u128);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '65536' into register \"r\"'s bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
)]
fn default_value_cannot_bit_into_bit_width_error_4() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 1);
r.default_value(65536u32);
}
#[test]
#[should_panic(
expected = "Attempted to drive register \"r\"'s next value with a signal from another module."
)]
fn drive_next_separate_module_error() {
let c = Context::new();
let m1 = c.module("A");
let l = m1.lit(true, 1);
let m2 = c.module("b");
let r = m2.reg("r", 1);
r.drive_next(l);
}
#[test]
#[should_panic(
expected = "Attempted to drive register \"r\"'s next value with a signal that has a different bit width than the register (5 and 3, respectively)."
)]
fn drive_next_incompatible_bit_width_error() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 3);
let i = m.input("i", 5);
r.drive_next(i);
}
#[test]
#[should_panic(
expected = "Attempted to drive register \"r\"'s next value in module \"A\", but this register's next value is already driven."
)]
fn drive_next_already_driven_error() {
let c = Context::new();
let m = c.module("A");
let r = m.reg("r", 32);
let i = m.input("i", 32);
r.drive_next(i);
r.drive_next(i);
}
}