use super::constant::*;
use super::context::*;
use super::instance::*;
use super::mem::*;
use super::register::*;
use super::signal::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::ptr;
#[must_use]
pub struct Module<'a> {
context: &'a Context<'a>,
pub(crate) name: String,
pub(crate) inputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
pub(crate) outputs: RefCell<BTreeMap<String, &'a Signal<'a>>>,
pub(crate) registers: RefCell<Vec<&'a Signal<'a>>>,
pub(crate) instances: RefCell<Vec<&'a Instance<'a>>>,
pub(crate) mems: RefCell<Vec<&'a Mem<'a>>>,
}
impl<'a> Module<'a> {
pub(super) fn new(context: &'a Context<'a>, name: String) -> Module<'a> {
Module {
context,
name,
inputs: RefCell::new(BTreeMap::new()),
outputs: RefCell::new(BTreeMap::new()),
registers: RefCell::new(Vec::new()),
instances: RefCell::new(Vec::new()),
mems: RefCell::new(Vec::new()),
}
}
pub fn lit<C: Into<Constant>>(&'a self, value: C, bit_width: u32) -> &Signal<'a> {
if bit_width < MIN_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a literal with {} bit(s). Signals must not be narrower than {} bit(s).",
bit_width, MIN_SIGNAL_BIT_WIDTH
);
}
if bit_width > MAX_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a literal with {} bit(s). Signals must not be wider than {} bit(s).",
bit_width, MAX_SIGNAL_BIT_WIDTH
);
}
let value = value.into();
let required_bits = value.required_bits();
if required_bits > bit_width {
let numeric_value = value.numeric_value();
panic!("Cannot fit the specified value '{}' into the specified bit width '{}'. The value '{}' requires a bit width of at least {} bit(s).", numeric_value, bit_width, numeric_value, required_bits);
}
self.context.signal_arena.alloc(Signal {
context: self.context,
module: self,
data: SignalData::Lit { value, bit_width },
})
}
pub fn low(&'a self) -> &Signal<'a> {
self.lit(false, 1)
}
pub fn high(&'a self) -> &Signal<'a> {
self.lit(true, 1)
}
pub fn input<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Signal<'a> {
let name = name.into();
if bit_width < MIN_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create an input with {} bit(s). Signals must not be narrower than {} bit(s).",
bit_width, MIN_SIGNAL_BIT_WIDTH
);
}
if bit_width > MAX_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create an input with {} bit(s). Signals must not be wider than {} bit(s).",
bit_width, MAX_SIGNAL_BIT_WIDTH
);
}
let input = self.context.signal_arena.alloc(Signal {
context: self.context,
module: self,
data: SignalData::Input {
name: name.clone(),
bit_width,
},
});
self.inputs.borrow_mut().insert(name, input);
input
}
pub fn output<S: Into<String>>(&'a self, name: S, source: &'a Signal<'a>) {
if !ptr::eq(self, source.module) {
panic!("Cannot output a signal from another module.");
}
self.outputs.borrow_mut().insert(name.into(), source);
}
pub fn reg<S: Into<String>>(&'a self, name: S, bit_width: u32) -> &Register<'a> {
if bit_width < MIN_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a register with {} bit(s). Signals must not be narrower than {} bit(s).",
bit_width, MIN_SIGNAL_BIT_WIDTH
);
}
if bit_width > MAX_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a register with {} bit(s). Signals must not be wider than {} bit(s).",
bit_width, MAX_SIGNAL_BIT_WIDTH
);
}
let data = self.context.register_data_arena.alloc(RegisterData {
module: self,
name: name.into(),
initial_value: RefCell::new(None),
bit_width,
next: RefCell::new(None),
});
let value = self.context.signal_arena.alloc(Signal {
context: self.context,
module: self,
data: SignalData::Reg { data },
});
self.registers.borrow_mut().push(value);
self.context.register_arena.alloc(Register { data, value })
}
pub fn mux(
&'a self,
cond: &'a Signal<'a>,
when_true: &'a Signal<'a>,
when_false: &'a Signal<'a>,
) -> &Signal<'a> {
if when_true == when_false {
return when_true;
}
if !ptr::eq(self, cond.module) {
panic!("Attempted to combine signals from different modules.");
}
if !ptr::eq(self, when_true.module) {
panic!("Attempted to combine signals from different modules.");
}
if !ptr::eq(self, when_false.module) {
panic!("Attempted to combine signals from different modules.");
}
if cond.bit_width() != 1 {
panic!("Multiplexer conditionals can only be 1 bit wide.");
}
if when_true.bit_width() != when_false.bit_width() {
panic!(
"Cannot multiplex signals with different bit widths ({} and {}, respectively).",
when_true.bit_width(),
when_false.bit_width()
);
}
self.context.signal_arena.alloc(Signal {
context: self.context,
module: self,
data: SignalData::Mux {
cond,
when_true,
when_false,
bit_width: when_true.bit_width(),
},
})
}
pub fn instance<S: Into<String>>(
&'a self,
instance_name: S,
module_name: &str,
) -> &Instance<'a> {
match self.context.modules.borrow().get(module_name) {
Some(instantiated_module) => {
let ret = self.context.instance_arena.alloc(Instance {
context: self.context,
module: self,
instantiated_module,
name: instance_name.into(),
driven_inputs: RefCell::new(BTreeMap::new()),
});
self.instances.borrow_mut().push(ret);
ret
}
_ => panic!("Attempted to instantiate a module identified by \"{}\", but no such module exists in this context.", module_name)
}
}
pub fn mem<S: Into<String>>(
&'a self,
name: S,
address_bit_width: u32,
element_bit_width: u32,
) -> &Mem<'a> {
if address_bit_width < MIN_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a memory with {} address bit(s). Signals must not be narrower than {} bit(s).",
address_bit_width, MIN_SIGNAL_BIT_WIDTH
);
}
if address_bit_width > MAX_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a memory with {} address bit(s). Signals must not be wider than {} bit(s).",
address_bit_width, MAX_SIGNAL_BIT_WIDTH
);
}
if element_bit_width < MIN_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a memory with {} element bit(s). Signals must not be narrower than {} bit(s).",
element_bit_width, MIN_SIGNAL_BIT_WIDTH
);
}
if element_bit_width > MAX_SIGNAL_BIT_WIDTH {
panic!(
"Cannot create a memory with {} element bit(s). Signals must not be wider than {} bit(s).",
element_bit_width, MAX_SIGNAL_BIT_WIDTH
);
}
let ret = self.context.mem_arena.alloc(Mem {
context: self.context,
module: self,
name: name.into(),
address_bit_width,
element_bit_width,
initial_contents: RefCell::new(None),
read_ports: RefCell::new(Vec::new()),
write_port: RefCell::new(None),
});
self.mems.borrow_mut().push(ret);
ret
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(
expected = "Cannot create a literal with 0 bit(s). Signals must not be narrower than 1 bit(s)."
)]
fn lit_bit_width_lt_min_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(false, 0);
}
#[test]
#[should_panic(
expected = "Cannot create a literal with 129 bit(s). Signals must not be wider than 128 bit(s)."
)]
fn lit_bit_width_gt_max_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(false, 129);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '128' into the specified bit width '7'. The value '128' requires a bit width of at least 8 bit(s)."
)]
fn lit_value_cannot_bit_into_bit_width_error_1() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(128u32, 7);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '128' into the specified bit width '2'. The value '128' requires a bit width of at least 8 bit(s)."
)]
fn lit_value_cannot_bit_into_bit_width_error_2() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(128u64, 2);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '1023' into the specified bit width '4'. The value '1023' requires a bit width of at least 10 bit(s)."
)]
fn lit_value_cannot_bit_into_bit_width_error_3() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(1023u128, 4);
}
#[test]
#[should_panic(
expected = "Cannot fit the specified value '65536' into the specified bit width '1'. The value '65536' requires a bit width of at least 17 bit(s)."
)]
fn lit_value_cannot_bit_into_bit_width_error_4() {
let c = Context::new();
let m = c.module("A");
let _ = m.lit(65536u32, 1);
}
#[test]
#[should_panic(
expected = "Cannot create an input with 0 bit(s). Signals must not be narrower than 1 bit(s)."
)]
fn input_width_lt_min_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.input("i", 0);
}
#[test]
#[should_panic(
expected = "Cannot create an input with 129 bit(s). Signals must not be wider than 128 bit(s)."
)]
fn input_width_gt_max_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.input("i", 129);
}
#[test]
#[should_panic(expected = "Cannot output a signal from another module.")]
fn output_separate_module_error() {
let c = Context::new();
let m1 = c.module("A");
let m2 = c.module("B");
let i = m2.high();
m1.output("a", i);
}
#[test]
#[should_panic(
expected = "Cannot create a register with 0 bit(s). Signals must not be narrower than 1 bit(s)."
)]
fn reg_bit_width_lt_min_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.reg("r", 0);
}
#[test]
#[should_panic(
expected = "Cannot create a register with 129 bit(s). Signals must not be wider than 128 bit(s)."
)]
fn reg_bit_width_gt_max_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.reg("r", 129);
}
#[test]
#[should_panic(expected = "Attempted to combine signals from different modules.")]
fn mux_cond_separate_module_error() {
let c = Context::new();
let a = c.module("A");
let l1 = a.lit(false, 1);
let b = c.module("B");
let l2 = b.lit(32u8, 8);
let l3 = b.lit(32u8, 8);
let _ = b.mux(l1, l2, l3);
}
#[test]
#[should_panic(expected = "Attempted to combine signals from different modules.")]
fn mux_when_true_separate_module_error() {
let c = Context::new();
let a = c.module("A");
let l1 = a.lit(32u8, 8);
let b = c.module("B");
let l2 = b.lit(true, 1);
let l3 = b.lit(32u8, 8);
let _ = b.mux(l2, l1, l3);
}
#[test]
#[should_panic(expected = "Attempted to combine signals from different modules.")]
fn mux_when_false_separate_module_error() {
let c = Context::new();
let a = c.module("A");
let l1 = a.lit(32u8, 8);
let b = c.module("B");
let l2 = b.lit(true, 1);
let l3 = b.lit(32u8, 8);
let _ = b.mux(l2, l3, l1);
}
#[test]
#[should_panic(expected = "Multiplexer conditionals can only be 1 bit wide.")]
fn mux_cond_bit_width_error() {
let c = Context::new();
let a = c.module("A");
let l1 = a.lit(2u8, 2);
let l2 = a.lit(32u8, 8);
let l3 = a.lit(32u8, 8);
let _ = a.mux(l1, l2, l3);
}
#[test]
#[should_panic(
expected = "Cannot multiplex signals with different bit widths (3 and 5, respectively)."
)]
fn mux_true_false_bit_width_error() {
let c = Context::new();
let a = c.module("A");
let l1 = a.lit(false, 1);
let l2 = a.lit(3u8, 3);
let l3 = a.lit(3u8, 5);
let _ = a.mux(l1, l2, l3);
}
#[test]
#[should_panic(
expected = "Attempted to instantiate a module identified by \"nope\", but no such module exists in this context."
)]
fn instantiate_nonexistent_module_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.instance("lol", "nope");
}
#[test]
#[should_panic(
expected = "Cannot create a memory with 0 address bit(s). Signals must not be narrower than 1 bit(s)."
)]
fn mem_address_bit_width_lt_min_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.mem("mem", 0, 1);
}
#[test]
#[should_panic(
expected = "Cannot create a memory with 129 address bit(s). Signals must not be wider than 128 bit(s)."
)]
fn mem_address_bit_width_gt_max_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.mem("mem", 129, 1);
}
#[test]
#[should_panic(
expected = "Cannot create a memory with 0 element bit(s). Signals must not be narrower than 1 bit(s)."
)]
fn mem_element_bit_width_lt_min_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.mem("mem", 1, 0);
}
#[test]
#[should_panic(
expected = "Cannot create a memory with 129 element bit(s). Signals must not be wider than 128 bit(s)."
)]
fn mem_element_bit_width_gt_max_error() {
let c = Context::new();
let m = c.module("A");
let _ = m.mem("mem", 1, 129);
}
}